[
  {
    "path": ".editorconfig",
    "content": "[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.{v,js,json}]\nindent_style = tab\n\n[*.md]\nmax_line_length = 100\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n*.bat eol=crlf\n\n**/*.v linguist-language=V\n**/*.vv linguist-language=V\n**/*.vsh linguist-language=V\n**/v.mod linguist-language=V\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "---\nname: 🐛 Bug Report\ndescription: Report a bug\ntitle: (please, provide bug report summary here)\nlabels: [ bug ]\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the bug\n      description: What is the problem? A clear and concise description of the bug.\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: What did you expect to happen?\n    validations:\n      required: true\n\n  - type: textarea\n    id: current\n    attributes:\n      label: Current Behavior\n      description: |\n        What actually happened?\n\n        Please include full errors, uncaught exceptions, stack traces, and relevant logs.\n        If service/functions responses are relevant, please include wire logs.\n    validations:\n      required: true\n\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: Reproduction Steps\n      description: |\n        Provide a self-contained, concise snippet of code that can be used to reproduce the issue.\n        For more complex issues provide a repo with the smallest sample that reproduces the bug.\n\n        Avoid including business logic or unrelated code, it makes diagnosis more difficult.\n        The code sample should be an SSCCE. See http://sscce.org/ for details.\n        In short, please provide a code sample that we can copy/paste, run and reproduce.\n    validations:\n      required: true\n\n  - type: textarea\n    id: solution\n    attributes:\n      label: Possible Solution\n      description: Suggest a fix/reason for the bug\n    validations:\n      required: false\n\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional Information/Context\n      description: |\n        Anything else that might be relevant for troubleshooting this bug.\n        Providing context helps us come up with a solution that is most useful in the real world.\n    validations:\n      required: false\n\n  - type: textarea\n    id: environment\n    attributes:\n      label: Environment details (`v doctor` output)\n    validations:\n      required: true\n\n  - type: input\n    id: editor-name\n    attributes:\n      label: Editor name\n    validations:\n      required: true\n\n  - type: input\n    id: v-analyzer-version\n    attributes:\n      label: v-analyzer Version\n      description: |\n        `v-analyzer --version` or in Command Palette: `v-analyzer: Show v-analyzer server version`\n    validations:\n      required: true\n\n  - type: input\n    id: vs-code-extension-version\n    attributes:\n      label: VS Code Extension Version\n      description: |\n        If you are using the VS Code extension, please provide the version of the extension.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 💬 General Questions and Answers about v-analyzer\n    url: https://github.com/vlang/v-analyzer/discussions/categories/q-a\n    about: You can ask and answer questions about v-analyzer in the discussions forum.\n\n  - name: 💬 V Discord Server\n    url: https://discord.gg/vlang\n    about: You can join our Discord server for real time discussion and support\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "---\nname: 🚀 Feature Request\ndescription: Suggest an idea for v-analyzer project\ntitle: \"(short issue description)\"\nlabels: [ feature-request ]\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the feature\n      description: A clear and concise description of the feature you are proposing.\n    validations:\n      required: true\n  - type: textarea\n    id: use-case\n    attributes:\n      label: Use Case\n      description: |\n        Why do you need this feature? For example: \"I'm always frustrated when...\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: other\n    attributes:\n      label: Other Information\n      description: |\n        Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/workflows/analyzer_tests.yml",
    "content": "name: Analyzer CI\n\non:\n  push:\n    paths-ignore:\n      - '.github/**'\n      - '!**/analyzer_tests.yml'\n      - '!**/version_test.vv'\n      - 'editors/code/**'\n      - '**/*.md'\n  pull_request:\n    paths-ignore:\n      - '.github/**'\n      - '!**/analyzer_tests.yml'\n      - '!**/version_test.vv'\n      - 'editors/code/**'\n      - '**/*.md'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    strategy:\n      matrix:\n        include:\n          - os: macos-latest\n            cc: clang\n          - os: ubuntu-latest\n            cc: gcc\n          - os: windows-latest\n            cc: gcc\n      fail-fast: false\n\n    runs-on: ${{ matrix.os }}\n    env:\n      VFLAGS: -cg -cc ${{ matrix.cc }}\n\n    steps:\n      - name: Install V\n        id: install-v\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n        with:\n          submodules: true\n\n      - name: Run tests\n        run: v test .\n\n      - name: Install v-analyzer\n        if: runner.os != 'Windows'\n        run: |\n          # Build and install v-analyzer at the head ref of the submitted changes.\n          v build.vsh\n          sudo mv ./bin/v-analyzer /usr/local/bin/v-analyzer\n          v-analyzer --version\n\n      - name: Verify version\n        # TODO: include Windows\n        if: runner.os != 'Windows'\n        run: v .github/workflows/version_test.vv\n"
  },
  {
    "path": ".github/workflows/build_ci.yml",
    "content": "name: Build CI\n\non:\n  push:\n    paths-ignore:\n      - '.github/**'\n      - '!**/build_ci.yml'\n      - '**/test/**'\n      - '**/tests/**'\n      - '**/*.md'\n      - '**/test_*.v'\n      - '**/*_test.v'\n  pull_request:\n    paths-ignore:\n      - '.github/**'\n      - '!**/build_ci.yml'\n      - '**/test/**'\n      - '**/tests/**'\n      - '**/*.md'\n      - '**/test_*.v'\n      - '**/*_test.v'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  build:\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n        mode: [debug, dev, release]\n      fail-fast: false\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Install V\n        id: install-v\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n        with:\n          submodules: true\n\n      - name: Build\n        run: v build.vsh ${{ matrix.mode }}\n\n      - name: Check if the build is successful\n        run: ./bin/v-analyzer --version\n"
  },
  {
    "path": ".github/workflows/install_ci.yml",
    "content": "name: Install CI\n\non:\n  push:\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  install:\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n      fail-fast: false\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Install V\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Install via webscript\n        run: v download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh\n\n      - name: Verify installation success\n        run: ~/.config/v-analyzer/bin/v-analyzer --version\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n\n      - name: Cleanup and prepare installation\n        shell: bash\n        run: |\n          rm -r ~/.config/v-analyzer/bin/v-analyzer\n          mkdir Downloads\n          mv ./install.vsh Downloads/install.vsh\n\n        # While the webscript installation step tests the general functionality of direct installation via the web,\n        # regressions related to the install script would only become visible AFTER pushing changes to the main branch.\n        # We reduce the potential for errors by simulating downloading the script and running it separately.\n      - name: Install via local script\n        run: cd Downloads && v install.vsh\n\n      - name: Verify installation success\n        run: ~/.config/v-analyzer/bin/v-analyzer --version\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\n\non:\n  push:\n    paths:\n      - '**.v'\n      - '**.vsh'\n      - '**/lint.yml'\n  pull_request:\n    paths:\n      - '**.v'\n      - '**.vsh'\n      - '**/lint.yml'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  fmt:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Install V\n        id: install-v\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n\n      - name: Verify formatting\n        run: |\n          set +e\n          v fmt -c .\n          exit_code=$?\n          # Don't fail on internal errors.\n          if [[ $exit_code -ne 0 && $exit_code -ne 5 ]]; then\n            v fmt -diff .\n            exit 1\n          fi\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n    tags:\n      - '*'\n    paths-ignore:\n      - '**/test/**'\n      - '**/tests/**'\n      - '**/test_*.v'\n      - '**/*_test.v'\n      - '**/*.md'\n      - '.github/**'\n      - '!**/release.yml'\n\npermissions:\n  contents: write\n\nenv:\n  PROJECT_NAME: v-analyzer\n\njobs:\n  build-v-analyzer:\n    strategy:\n      matrix:\n        target: [linux-x86_64, darwin-x86_64, darwin-arm64, windows-x86_64]\n        build_type: [dev, debug, release]\n        include:\n          - target: windows-x86_64\n            os: windows-latest\n            bin_ext: .exe\n          - target: linux-x86_64\n            os: ubuntu-latest\n          - target: darwin-x86_64\n            os: macos-13\n          - target: darwin-arm64\n            os: macos-latest\n          - build_type: release\n            cflags: -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -frename-registers -ftree-vectorize\n      fail-fast: false\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Install V\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n        with:\n          submodules: true\n\n      - name: Compile ${{ matrix.build_type }} build\n        id: compile\n        env:\n          CFLAGS: ${{ matrix.cflags }} -pipe\n          VFLAGS: ${{ matrix.vflags }}\n        shell: bash\n        run: |\n          v build.vsh ${{ matrix.build_type }}\n          if [[ \"${{ matrix.os }}\" != \"macos-latest\" ]]; then\n            strip --strip-unneeded ./bin/v-analyzer${{ matrix.bin_ext }}\n            strip --discard-all ./bin/v-analyzer${{ matrix.bin_ext }}\n          fi\n          if [[ \"${{ matrix.build_type }}\" != \"release\" ]]; then\n            echo \"SUFFIX=-${{ matrix.build_type }}\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      - name: Create artifact\n        env:\n          ARTIFACT_NAME: ${{ env.PROJECT_NAME }}-${{ matrix.target }}${{ steps.compile.outputs.SUFFIX }}\n        shell: bash\n        run: 7z a -tzip ${{ env.ARTIFACT_NAME }}.zip ./bin/v-analyzer${{ matrix.bin_ext }}\n\n      - name: Upload artifact\n        uses: actions/upload-artifact@v4\n        env:\n          ARTIFACT_NAME: ${{ env.PROJECT_NAME }}-${{ matrix.target }}${{ steps.compile.outputs.SUFFIX }}\n        with:\n          name: ${{ env.ARTIFACT_NAME }}\n          path: ${{ env.ARTIFACT_NAME }}.zip\n\n  build-vscode:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Install Nodejs\n        uses: actions/setup-node@v4\n        with:\n          node-version: 20\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n\n      - name: Compile\n        id: compile\n        shell: bash\n        run: |\n          pushd editors/code\n          version=$(sed -E -n 's/^\\s+\"version\": \"([^\"]+)\".*/\\1/gp' package.json)\n          echo \"VERSION=$version\" >> \"$GITHUB_OUTPUT\"\n          retry=0\n          echo \"[+] Install dependencies\"\n          npm install\n          echo \"[+] Package start\"\n          set +e\n          while [[ ${retry} < 3 ]]; do\n            if npm run package; then\n              echo \"[+] Package done\"\n              break\n            else\n              sleep 1\n              let retry++\n              echo \"[+] Package fail, ${retry} retry\"\n            fi\n          done\n          set -e\n          popd\n\n      - name: Upload artifact\n        uses: actions/upload-artifact@v4\n        env:\n          ARTIFACT_NAME: vscode-${{ env.PROJECT_NAME }}-${{ steps.compile.outputs.VERSION }}\n        with:\n          name: ${{ env.ARTIFACT_NAME }}\n          path: editors/code/${{ env.ARTIFACT_NAME }}.vsix\n\n  release:\n    runs-on: ubuntu-latest\n    needs: [build-v-analyzer, build-vscode]\n\n    steps:\n      - name: Download artifacts\n        uses: actions/download-artifact@v4\n        with:\n          path: ${{ env.PROJECT_NAME }}\n          merge-multiple: true\n\n      - name: Update nightly tag\n        if: github.ref_type != 'tag'\n        uses: richardsimko/update-tag@v1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: nightly\n\n      - name: Generate development release body\n        if: github.ref_type != 'tag'\n        id: generate_body\n        shell: bash\n        run: |\n          now=$(date -u +'%Y-%m-%d %H:%M:%S UTC')\n          echo \"BODY=Generated on <samp>$now</samp> from commit ${{ github.sha }}.\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Release development version\n        if: github.ref_type != 'tag'\n        uses: ncipollo/release-action@v1\n        with:\n          artifacts: ${{ env.PROJECT_NAME }}/*\n          tag: nightly\n          body: ${{ steps.generate_body.outputs.BODY }}\n          name: v-analyzer development build\n          allowUpdates: true\n          prerelease: true\n\n      - name: Release latest version\n        if: github.ref_type == 'tag'\n        uses: ncipollo/release-action@v1\n        with:\n          artifacts: ${{ env.PROJECT_NAME }}/*\n          allowUpdates: true\n          omitBodyDuringUpdate: true\n          omitNameDuringUpdate: true\n"
  },
  {
    "path": ".github/workflows/tree_sitter_v.yml",
    "content": "name: Tree-sitter CI\n\non:\n  push:\n    paths:\n      - 'tree_sitter_v/**'\n      - '**/test_tree_sitter_v.yml'\n  pull_request:\n    paths:\n      - 'tree_sitter_v/**'\n      - '**/test_tree_sitter_v.yml'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  test-grammar:\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: tree_sitter_v\n\n    steps:\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n\n      - name: Install dependencies\n        run: npm update\n\n      - name: Run tests\n        run: npm run test\n\n  test-bindings:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Install V\n        id: install-v\n        uses: vlang/setup-v@v1.4\n        with:\n          check-latest: true\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n        with:\n          submodules: true\n\n      - name: Run tests\n        run: v test tree_sitter_v/bindings\n\n      - name: Run examples\n        run: |\n          cd tree_sitter_v\n          exit_code=0\n          for example in $(find -wholename '*/examples/*.v'); do\n            v run $example\n            if [ $? -ne 0 ]; then\n              exit_code=1\n              echo $exit_code\n              echo \"Failed to run example \\`$example\\`\"\n            fi\n          done\n          exit $exit_code\n"
  },
  {
    "path": ".github/workflows/version_test.vv",
    "content": "import os\nimport v.vmod\n\nfn test_version() {\n\tif os.getenv('CI') != 'true' {\n\t\teprintln('WARNING: expecting usage in combination with CI workflow.')\n\t}\n\n\tfor k, v in os.environ() {\n\t\tprintln('>>> env key: ${k} | value: ${v}')\n\t}\n\n\tsha := os.getenv('GITHUB_WORKFLOW_SHA')\n\tassert sha.len > 10\n\tgit_ref := sha.trim_space()[..7]\n\n\tmanifest := vmod.decode(@VMOD_FILE)!\n\tassert manifest.name == 'v-analyzer'\n\n\t// Move out of the project directory to ensure that we exclude the possiblity of\n\t// deriving the commit reference from v-analyzer's directory at program startup.\n\tos.chdir('/tmp/')!\n\tanalyzer_version := os.execute_opt('v-analyzer --version')!.output.all_after_last(' ').trim_space()\n\n\tassert '${manifest.version}.${git_ref}' == analyzer_version\n}\n"
  },
  {
    "path": ".github/workflows/vscode_extension_tests.yml",
    "content": "name: VS Code Extension CI\n\non:\n  push:\n    paths:\n      - 'editors/code/**'\n      - '**/vscode_extension_tests.yml'\n  pull_request:\n    paths:\n      - 'editors/code/**'\n      - '**/vscode_extension_tests.yml'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n      fail-fast: false\n\n    name: Test VS Code Extension on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Install Nodejs\n        uses: actions/setup-node@v4\n        with:\n          node-version: 20\n\n      - name: Checkout v-analyzer\n        uses: actions/checkout@v4\n\n      - name: Install dependencies\n        run: cd editors/code && npm update\n\n      - name: Run tests\n        run: cd editors/code && npm run test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Binaries for programs and plugins\nmain\nv-analyzer\n**/*.exe\n**/*.exp\n**/*.exe~\n**/*.so\n**/*.dylib\n**/*.dll\n**/*.log\n**/*.lib\n**/*.obj\n\n# Ignore binary output folders\nbin\nbuild\n\n# Ignore cache folders\ncache\n\n# Ignore common editor/system specific metadata\n.DS_Store\n.idea\n.vscode\n*.iml\n\n# ENV\n.env\n\n# vweb and database\n*.db\n\n# generated executables on unix:\ninstall\ngenerate_types\ncmd/v-analyzer/v-analyzer\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"tree_sitter_v/bindings/core\"]\n\tpath = tree_sitter_v/bindings/core\n\turl = https://github.com/tree-sitter/tree-sitter.git\n"
  },
  {
    "path": ".v-analyzer/config.toml",
    "content": "# Specifies the path to the V installation directory with `v` executable.\n# If not set, the plugin will try to find it on its own.\n# Basically, you don't need to set it.\n#custom_vroot = \"~/v\"\n\n# Specifies the path where to store the cache.\n# By default, it is stored in the system's cache directory.\n# You can set it to `./` to store the cache in the project's directory, this is useful\n# if you want to debug the analyzer.\n# Basically, you don't need to set it.\ncustom_cache_dir = \"./cache\"\n\n# Specifies whenever to enable semantic tokens or not.\n# - `full` — enables all semantic tokens. In this mode analyzer resolves all symbols\n#    in the file to provide the most accurate highlighting.\n# - `syntax` — enables only syntax tokens, such tokens highlight structural elements\n#    such as field names or import names.\n#    The fastest option, which is always enabled when the file contains more than 1000 lines.\n# - `none` — disables semantic tokens.\n# By default, `full` for files with less than 1000 lines, `syntax` for files with more.\nenable_semantic_tokens = \"full\"\n\n# Specifies inlay hints to show.\n[inlay_hints]\n# Specifies whenever to enable inlay hints or not.\n# By default, they are enabled.\nenable = true\n\n# Specifies whenever to show type hints for ranges or not.\n# Example:\n# ```\n# 0 ≤ .. < 10\n#   ^    ^\n# ```\n# or:\n# ```\n# a[0 ≤ .. < 10]\n#     ^    ^\n# ```\nenable_range_hints = true\n\n# Specifies whenever to show type hints for variables or not.\n# Example:\n# ```\n# name : Foo := foo()\n#      ^^^^^\n# ```\nenable_type_hints = true\n\n# Specifies whenever to show hints for implicit err variables or not.\n# Example:\n# ```\n# foo() or { err ->\n#            ^^^^^^\n# }\n# ```\nenable_implicit_err_hints = true\n\n# Specifies whenever to show hints for function parameters in call or not.\n# Example:\n# ```\n# fn foo(a int, b int) int {}\n#\n# foo(a: 1, b: 2)\n#     ^^    ^^\nenable_parameter_name_hints = true\n\n# Specifies whenever to show type hints for constants or not.\n# Example:\n# ```\n# const foo : int = 1\n#           ^^^^^\n# ```\nenable_constant_type_hints = true\n\n# Specifies whenever to show hints for enum field values or not.\n# Example:\n# ```\n# enum Foo {\n#   bar = 0\n#       ^^^\n#   baz = 1\n#       ^^^\n# }\n# ```\nenable_enum_field_value_hints = true\n\n# Specifies code lenses to show.\n[code_lens]\n# Specifies whenever to enable code lenses or not.\n# By default, they are enabled.\nenable = true\n\n# Specifies whenever to show code lenses for main function to run current directory or not.\n# Example:\n# ```\n# ▶ Run\n# fn main() {}\n# ```\nenable_run_lens = true\n\n# Specifies whenever to show code lenses for interface inheritors or not.\n# Example:\n# ```\n# 2 implementations\n# interface Foo {}\n# ```\nenable_inheritors_lens = true\n\n# Specifies whenever to show code lenses for structs implementing interfaces or not.\n# Example:\n# ```\n# implemented 2 interfaces\n# struct Boo {}\n# ```\nenable_super_interfaces_lens = true\n\n# Specifies whenever to show code lenses for test functions to run test or whole file or not.\n# Example:\n# ```\n# ▶ Run test | all file tests\n# fn test_foo() {}\n# ```\n# Note: \"all file tests\" is shown only for the first test function in the file.\nenable_run_tests_lens = true\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# v-analyser Changelog\n\n## [0.0.6] - 2025/02/27\nSixth public release.\n\nThis release contains mainly installation issue fixes.\nYou can now install it on all platforms, using an uniform command:\n`v download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh`\nIt also has improvements to the diagnostic output of the build and install scripts.\nV-analyzer has also been fixed to compile with the latest and stricter V versions.\nThe last notable change is the upgrade of our tree_sitter bindings.\n\n## [0.0.5] - 2024/11/13\nFifth public release.\n\n### New features and enhancements:\n∙ analyzer: add module index paths and wrapper module path as code block (#102)\n∙ analyzer: add `pub` access modifier to publicly used struct fields (#85)\n∙ analyzer: create vtmp directory for check-updates/up commands (#125)\n∙ analyzer: fix anonymous functions are self-invoking type mismatch (#48)\n∙ analyzer: fix build for paths with spaces (#83)\n∙ analyzer: Fix `code_description` (fixes zed-v) (#119)\n∙ analyzer: fix doc_comment_extractor (#50)\n∙ analyzer: fix vmodules_root check in setup_vpaths (#95)\n∙ analyzer: fix work progress shown as 0% when finishing indexing (#84)\n∙ analyzer: improve setup, extend client and log messages (#100)\n∙ analyzer: merge creation of vtmp directory for check-updates/up commands (#126)\n∙ analyzer: move const used to download install.vsh script (#127)\n∙ analyzer: reduce nesting in setup_toolchain\n∙ analyzer: rework path handling to simplify and reduce load (#86)\n∙ analyzer: simplify, improve completion context detection\n∙ analyzer: simplify, remove unnecessary abstraction\n∙ analyzer: update deprecated\n∙ analyzer: update deprecated unix time access (#99)\n∙ analyzer: use latest install script when updating (#81)\n∙ analyzer: support shebang syntax (#34)\n∙ analyzer: add inline struct field comments (#52)\n∙ analyzer: use build version aware caching (#57)\n∙ analyzer: update parser.c to align with the current development state (#13), \n            fixes highlighting for code in between 2 block comments\n∙ build: follow a default directory structure for V projects (#25)\n∙ build: update install.vsh to make repeated usage of path expand fn obsolete (#24)\n∙ install: add debug and dev binaries install (#60)\n∙ install: update the `git clone` options for install.vsh\n∙ server: add `range_clause` highlight (#9)\n∙ tree_sitter: correctly recognize shebang (#26)\n∙ tree_sitter: support `for mut is` clause (#77)\n∙ tree_sitter: support short lambda (#56)\n∙ tree_sitter: detach shebang from comment (#32)\n\n### Fixes to existing features:\n∙ fix: building of IndexingRoot.v\n∙ fix: fix behaviour of pascal_case_to_snake_case after V commit 5329a0a67\n∙ fix: fix goto definition for field names. (#135)\n∙ fix: fix hanging on vfmt-ing large files on windows (#130)\n∙ fix: fix install.vsh\n∙ fix: fix module index by making sure to index also src/ and modules/ folders too (#138)\n∙ fix: fix raw string with `\\` (#64)\n∙ fix: fix wrong macos target in release CI (#139)\n∙ fix: move tools/project-checker.v to its corresponding directory\n∙ fix: remove obsolete v.mod file in metadata submod\n∙ fix: resolve compiler complaints (#27)\n∙ fix: restore `.v` extensions for metadata/stubs, add test (#74)\n∙ fix: src/analyzer/index/IndexingRoot.v\n∙ fix: tree-sitter bindings examples, extend workflow to run examples\n∙ fix: update npm `generate` script\n∙ fix: version regression after eae3f91, add test (#61)\n∙ tree_sitter: fix issuse bug (#42)\n∙ tree_sitter: fix parser error on unescaped dollar identifier in string literals, add test (#79)\n∙ tree_sitter: fix parsing of nested comments, extend tests (#76)\n∙ tree_sitter: fix qualified type (#8)\n∙ tree_sitter: rewrite comment grammar, detach line- and block comments (#71)\n∙ tree_sitter: add sum type to tree node (#87)\n\n### Documentation:\n∙ docs: update README.md with more detailed instructions about\n        how to clone the project locally, fix `v check-md` warnings\n∙ docs: fix for Neovim LSP/Mason (#122)\n∙ docs: fix typo in readme\n∙ docs: make submodule info in readme better visible and its commands easier to copy\n∙ docs: refine readme before a potential structural update\n∙ docs: update readme badges (#38)\n∙ docs: update README.md mason install instructions (from https://github.com/v-analyzer/v-analyzer/pull/102)\n∙ docs: update workflow path in tree-sitter badge\n\n### Others:\n∙ chore: fix typos (#44)\n∙ chore: format all the files with the new fmt (#112)\n∙ chore: format all the files with the new vfmt (#117)\n∙ chore: format all the files with the new vfmt (#120)\n∙ chore: format all the files with the new vfmt (#121)\n∙ chore: run `v fmt -w install.vsh`\n∙ chore: remove obsolete `.editorconfig` file in subdir, format\n∙ chore: remove useless `compiler_flag` and copy `.exe` on windows (#108)\n∙ chore: run the linter CI for changes made to just .vsh files too\n∙ chore: updare editors/code dependencies (#33)\n∙ chore: update deprecated `index_last` to `last_index` (#72)\n∙ chore: update .gitattributes (#70)\n∙ chore: update tree-sitter dependencies (#31)\n∙ chore: use `.vv` extension for meta- and testdata files (#53)\n∙ ci: add concurrency config (#67)\n∙ ci: add linting and formatting automation to tree-sitter_v (#68)\n∙ ci: add retry to release/build-vscode (#54)\n∙ ci: add step to verify code formatting (#66)\n∙ ci: add `.vsix` artifacts to release asset uploads (#47)\n∙ ci: change `actions/upload-artifact@v3` to `actions/upload-artifact@v4` (#20)\n∙ ci: change `vlang/setup-v@v1.3` to `vlang/setup-v@v1.4` (#19)\n∙ ci: extend coverage in workflows\n∙ ci: extend release workflow; automate assets uploads on tag creation (#39)\n∙ ci: fix binary path in nightly ci (#36)\n∙ ci: make sure that install_ci.yml is run for every change.\n∙ ci: simplify, cover CI changes (#30)\n∙ ci: use dedicated lint workflow to verify formatting (#97)\n∙ refactor: decouple tree_sitter grammar and bindings (#37)\n∙ refactor: simplify doc_comment_extractor, reduce load (#51)\n∙ refactor: simplify grammar for `in/!in` and `is/!is`\n∙ refactor: simplify path handling, remove unused utils (#40)\n∙ refactor: store project metadata in metadata module (#59)\n∙ refactor: update project structure (#69)\n∙ tests: add test for the toolchain path setup (#96)\n∙ tests: fix paths in bindings test, add test to workflow\n∙ tests: fix analyzer test (#92)\n∙ tests: update testdata (#45)\n∙ tests: update tests to run with `v test` (#46)\n∙ tree_sitter: add .prettierignore (#89)\n∙ tree_sitter: improve clarity and quality of grammar (#78)\n∙ tree_sitter: improve selector expression grammar\n∙ tree_sitter: minimal cleanup, add optional `;` support between statements in {} blocks (#88)\n∙ tree_sitter: Update dependencies (#18)\n∙ tree_sitter: update tree-sitter-cli version to 0.22.2 (#41)\n\n\n## [0.0.4-beta.1] - 2024/01/09\nForth public release.\n\nNote: this is still a beta version, do expect bugs, and report them in\nour [issues tracker](https://github.com/vlang/v-analyzer/issues) .\n\n### Syntax enhancements & bug fixes:\n∙ Update comment rule (#5).\n∙ Fix string interpolation.\n∙ Fix comment string parse error (https://github.com/v-analyzer/v-analyzer/pull/85).\n∙ Fix attribute shading (#2).\n∙ Fix `parameters`.\n∙ Fix the type descriptions in the primitives.v stub.\n∙ Simplify `handle_jsonrpc` (https://github.com/v-analyzer/v-analyzer/pull/86).\n\n### VSCode Extension:\n∙ Show the full path to the found v-analyzer binary,\n  when the VSCode extension runs its bootstrap, to make\n  diagnosing problems easier.\n∙ Update the vscode extension package to vscode-v-analyzer-0.0.4.vsix\n\n### CI enhancements:\n∙ Use `ubuntu-20.04` for building the executables, to be compatible with more Linux distros.\n∙ Use `v build.vsh debug` for nightly releases, so the executables produce usable backtraces.\n∙ Silence the nightly releases, simplify the .yml script that builds\n  them (https://github.com/v-analyzer/v-analyzer/pull/83).\n\n### Others:\n∙ Update README.md to also include instructions for the mason.nvim Neovim\n  package manager (https://github.com/v-analyzer/v-analyzer/pull/90).\n∙ Fix notices and warnings with latest V.\n∙ Exclude .git/* and `_test.v` files from indexing by the language server,\n  see (https://github.com/v-analyzer/v-analyzer/pull/89).\n∙ Use a git submodule for https://github.com/tree-sitter/tree-sitter.git, see\n  (https://github.com/v-analyzer/v-analyzer/pull/81).\n∙ Use gcc for building on windows (https://github.com/v-analyzer/v-analyzer/pull/87).\n∙ Update build scripts (https://github.com/v-analyzer/v-analyzer/pull/84).\n∙ Fix version comparison in install.vsh .\n∙ Migrate from https://github.com/v-analyzer/v-analyzer/ to https://github.com/vlang/v-analyzer/ .\n\n## [0.0.3-beta.1] - 2023/12/13\nThird public release.\n\n### Syntax enhancements & bug fixes:\n∙ Fix support for multiline comments (https://github.com/v-analyzer/v-analyzer/pull/75)\n∙ Fix interface ref type highlight (https://github.com/v-analyzer/v-analyzer/pull/76)\n∙ Fix support for struct field attributes (https://github.com/v-analyzer/v-analyzer/pull/74)\n∙ Fix interface embeds and interface fields (https://github.com/v-analyzer/v-analyzer/pull/78)\n∙ Fix `assert cond, message` statements (https://github.com/v-analyzer/v-analyzer/pull/65)\n∙ Support @[attribute], fix signature, fix interface highlights\n\n### Language server enhancements:\n∙ Enable exit commands, to prevent lingering v-analyzer processes after\nan editor restart (https://github.com/v-analyzer/v-analyzer/pull/77)\n∙ server: fix NO_RESULT_CALLBACK_FOUND in neovim (https://github.com/v-analyzer/v-analyzer/pull/59)\n∙ Build the v-analyzer executable on linux as static in release mode, to\nmake it more robust and usable in more distros.\n\n### Others:\n∙ docs: add neovim install instructions (https://github.com/v-analyzer/v-analyzer/pull/63)\n∙ CI improvements, to make releases easier, and to keep the code quality high.\n∙ Update the vscode extension package to vscode-v-analyzer-0.0.3.vsix\n∙ Make `v-analyzer --version` show the build commit as well.\n\nNote: this is still a beta version, expect bugs and please report them in\nour [issues tracker](https://github.com/vlang/v-analyzer/issues) .\n\n## [0.0.2-beta.1] - 2023/11/21\nSecond public release. \n\nSmall internal improvements to the documentation, ci, build scripts.\n\nFix compilation with latest V.\n\nUpdate https://github.com/v-analyzer/v-tree-sitter from the latest\nupstream version from https://github.com/tree-sitter/tree-sitter .\n\nThis is still a beta version, expect bugs and please report them in\nour [issues tracker](https://github.com/vlang/v-analyzer/issues) .\n\n\n## [0.0.1-beta.1] - 2023/07/03\n\nFirst public release.\n\nPlease note that this is a beta version, so it may contain any bugs.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 V Open Source Community Association (VOSCA)\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": "<img width=\"200px\" src=\"https://github.com/vlang/v-analyzer/blob/2d5d12e4b82ce8d695576957145ff27a33a988c2/docs/cover-light.png#gh-light-mode-only\">\n<img width=\"200px\" src=\"https://github.com/vlang/v-analyzer/blob/2d5d12e4b82ce8d695576957145ff27a33a988c2/docs/cover-dark.png#gh-dark-mode-only\">\n\n# v-analyzer\n\n[![][badge__vscode_ext]](https://marketplace.visualstudio.com/items?itemName=VOSCA.vscode-v-analyzer)\n[![][badge__build_ci]](https://github.com/vlang/v-analyzer/actions/workflows/build_ci.yml?query=branch%3Amain)\n[![][badge__tests_ci]](https://github.com/vlang/v-analyzer/actions/workflows/analyzer_tests.yml?query=branch%3Amain)\n[![][badge__tree_sitter_ci]](https://github.com/vlang/v-analyzer/actions/workflows/tree_sitter_v.yml?query=branch%3Amain)\n[![][badge__vscode_ext_ci]](https://github.com/vlang/v-analyzer/actions/workflows/vscode_extension_tests.yml?query=branch%3Amain)\n\nBring IDE features for the V programming language to VS Code, Vim, and other editors.\n\nThe features provided by v-analyzer include:\n\n- code completion/IntelliSense\n- go to definition, type definition\n- find all references, document symbol, symbol renaming\n- types and documentation on hover\n- inlay hints for types and some construction like `or` block\n- semantic syntax highlighting\n- formatting\n- signature help\n\n## Installation\n\n### Linux, macOS, Windows\nNote: the following command will download `install.vsh` to the current directory, then \nrun it, and then *delete it*. If there is a pre-existing file with this name, make sure it\nis safe, when it is overwritten/deleted, or change the current directory (the script itself\ncan be run from anywhere).\n\n```sh \nv download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh\n```\n\nNote: if you get messages about `response does not start with HTTP/`, try going to the\nmain V repository, then do `./v -d use_openssl cmd/tools/vdownload.v` .\nAfter that, retry the same command:\n```sh \nv download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh\n```\n\n## Pre-built binaries\n\nYou can download pre-built binaries from the [release page](https://github.com/vlang/v-analyzer/releases).\nCurrently, we provide binaries for Linux (x64), macOS (x64 and ARM), and Windows (x64).\n\n## Building from source\n\n> [!NOTE]\n> This repository uses Git submodules.\n> In practice, this means that you either have to:\n>\n> ```sh\n> git clone --filter=blob:none --recursive --shallow-submodules https://github.com/vlang/v-analyzer\n> ```\n>\n> ... or, if you used just `git clone https://github.com/vlang/v-analyzer`, you can execute below\n> inside your local `v-analyzer` clone:\n>\n> ```sh\n> git submodule init && git submodule update\n> ```\n>\n> If you do not do either, the symptom is that when you try to build v-analyzer, you will get a\n> C compiler message, about `lib.c not found`\n\n> [!TIP]\n> On Windows, use GCC for building, as TCC can run into some issues.\n\nUpdate V to the latest version:\n\n```bash\nv up\n```\n\nYou can build a debug or release version of the binary.\nThe debug version will be slower, but faster to compile.\n\n```bash\nv build.vsh debug\n```\n\n```bash\nv build.vsh release\n```\n\nThe compiled binary will be located in the `bin/` folder.\n\n## Setup\n\nAdd the `bin/` folder to your `$PATH` environment variable to make the `v-analyzer` command easily\naccessible.\n\nYou can also specify the path to the binary in your VS Code settings:\n\n```json\n{\n\t\"v-analyzer.serverPath\": \"/path/to/v-analyzer/bin/v-analyzer\"\n}\n```\n\n> **Note**\n> Restart VS Code after changing the settings or PATH.\n\n### Config\n\nv-analyzer is configured using global or local config.\nThe global config is located in `~/.config/v-analyzer/config.toml`, changing it will affect all\nprojects.\n\nA local config can be created with the `v-analyzer init` command at the root of the project.\nOnce created, it will be in `./.v-analyzer/config.toml`.\nEach setting in the config has a detailed description.\n\nPay attention to the `custom_vroot` setting, if v-analyzer cannot find where V was installed, then\nyou will need to specify the path to it manually in this field.\n\n## Updating\n\nTo update `v-analyzer` to the latest version, run:\n\n```bash\nv-analyzer up\n```\n\nYou can also update to a nightly version:\n\n```bash\nv-analyzer up --nightly\n```\n\n> **Note**\n> In the nightly version you will get the latest changes, but they may not be stable!\n\n## VS Code extension\n\nThe VS Code extension is available via the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=VOSCA.vscode-v-analyzer).\nThe source code for extension is contained in the [`editors/code`](https://github.com/vlang/v-analyzer/tree/main/editors/code) folder of this repository.\n\n## NVIM LSP / Mason\n\nFor Neovim users, v-analyzer is available via [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#v_analyzer) plugin.\nIt is part of the [mason registry](https://mason-registry.dev/registry/list#v-analyzer) and could be installed with both Neovim plugins:\n- [mason.nvim](https://github.com/williamboman/mason.nvim) with `:MasonInstall v-analyzer` command\n- [mason-lspconfig.nvim](https://github.com/williamboman/mason-lspconfig.nvim) with `:LspInstall` command\n\n## Authors\n\n- `jsonrpc`, `lsp`, `tree_sitter_v` modules written initially by\n  [VLS authors](https://github.com/vlang/vls) and after that in 2023 it was modified by the\n  [VOSCA](https://github.com/vlang-association).\n\n## Thanks\n\n- [VLS](https://github.com/vlang/vls) authors for the initial Language Server implementation!\n- [vscode-vlang](https://github.com/vlang/vscode-vlang) authors for the first VS Code extension!\n- [rust-analyzer](https://github.com/rust-lang/rust-analyzer) and [gopls](https://github.com/golang/tools/tree/master/gopls) for the inspiration!\n- [Tree-sitter](https://github.com/tree-sitter/tree-sitter) authors for the cool parsing library!\n\n## License\n\nThis project is under the **MIT License**.\nThe full license text can be found in the [LICENSE](https://github.com/vlang/v-analyzer/blob/main/LICENSE) file.\n\n[badge__vscode_ext]: https://img.shields.io/badge/VS_Code-extension-1da2e2?logo=visualstudiocode&logoWidth=11&logoColor=959da5&labelColor=333\n[badge__build_ci]: https://img.shields.io/github/actions/workflow/status/vlang/v-analyzer/build_ci.yml?style=flat-rounded&branch=main&logo=github&&logoColor=959da5&labelColor=333&label=Build\n[badge__tests_ci]: https://img.shields.io/github/actions/workflow/status/vlang/v-analyzer/analyzer_tests.yml?style=flat-rounded&branch=main&logo=github&&logoColor=959da5&labelColor=333&label=Analyzer\n[badge__tree_sitter_ci]: https://img.shields.io/github/actions/workflow/status/vlang/v-analyzer/tree_sitter_v.yml?style=flat-rounded&branch=main&logo=github&&logoColor=959da5&labelColor=333&label=Tree-sitter\n[badge__vscode_ext_ci]: https://img.shields.io/github/actions/workflow/status/vlang/v-analyzer/vscode_extension_tests.yml?style=flat-rounded&branch=main&logo=github&&logoColor=959da5&labelColor=333&label=VS%20Code%20Extension\n"
  },
  {
    "path": "build.vsh",
    "content": "#!/usr/bin/env -S v\n\n// This script is used to build the v-analyzer binary.\n// Usage: `v build.vsh [debug|dev|release]`\n// By default, doing just `v build.vsh` will use debug mode.\nimport os\nimport cli\nimport term\nimport time\nimport src.metadata\n\nconst vexe = @VEXE\nconst bin_path = './bin/v-analyzer' + $if windows { '.exe' } $else { '' }\nconst build_time = time.now()\nconst build_commit = get_build_commit()\nconst build_datetime = build_time.format_ss()\n\nconst gcheck = term.bold(term.green('✓'))\nconst ynote = term.bold(term.gray('ⓘ '))\nconst is_nixos = os.exists('/etc/NIXOS')\n\nenum ReleaseMode {\n\trelease\n\tdebug\n\tdev\n}\n\nfn get_build_commit() string {\n\t// In pull requests, GA creates a merge commit, to test the latest changes,\n\t// as if they would have been merged in the main branch. However for building\n\t// and version checking, we need the commit hash of the actual last change in the PR.\n\tcommittish := os.getenv_opt('GITHUB_WORKFLOW_SHA') or { 'HEAD' }\n\treturn os.execute('git rev-parse --short ${committish}').output.trim_space()\n}\n\nfn eline(msg string) {\n\teprintln('${term.bold(term.red('[ERROR]'))} ${msg}')\n}\n\nfn detect_build_os() {\n\t$if windows {\n\t\tprintln('${ynote} Detected Windows .')\n\t}\n\t$if macos {\n\t\tprintln('${ynote} Detected macOS .')\n\t}\n\t$if linux {\n\t\tprintln('${ynote} Detected Linux .')\n\t}\n\t$if freebsd {\n\t\tprintln('${ynote} Detected FreeBSD .')\n\t}\n\tif is_nixos {\n\t\tprintln('${ynote} NIXOS detected ... The build *should NOT* be static .')\n\t}\n}\n\nfn (m ReleaseMode) compile_cmd() string {\n\tbase_build_cmd := '${os.quoted_path(@VEXE)} ${os.quoted_path(@VMODROOT)} -o ${quoted_path(bin_path)} -no-parallel'\n\tcc := if v := os.getenv_opt('CC') {\n\t\t'-cc ${v}'\n\t} else {\n\t\t$if windows {\n\t\t\t// TCC cannot build tree-sitter on Windows.\n\t\t\t'-cc gcc'\n\t\t} $else $if linux {\n\t\t\t// GCC is needed for libbacktrace (unwind.h) and tree-sitter support.\n\t\t\t'-cc gcc'\n\t\t} $else {\n\t\t\t// Let `-prod` toggle the appropriate production compiler.\n\t\t\t''\n\t\t}\n\t}\n\n\tcflags := $if cross_compile_macos_arm64 ? {\n\t\t'-cflags \"-target arm64-apple-darwin\"'\n\t} $else $if cross_compile_macos_x86_64 ? {\n\t\t'-cflags \"-target x86_64-apple-darwin\"'\n\t} $else $if linux {\n\t\tif !is_nixos && m == .release {\n\t\t\t'-cflags -static'\n\t\t} else {\n\t\t\t''\n\t\t}\n\t} $else {\n\t\t''\n\t}\n\n\tlibbacktrace := $if windows { '' } $else { '-d use_libbacktrace' }\n\tbuild_cmd := '${base_build_cmd} ${cc} ${cflags}'.trim_space()\n\tmut resulting_cmd := match m {\n\t\t.release { '${build_cmd} -prod' }\n\t\t.debug { '${build_cmd} -g ${libbacktrace}' }\n\t\t.dev { '${build_cmd} -d show_ast_on_hover -g ${libbacktrace}' }\n\t}\n\n\t$if !windows {\n\t\t// Treesitter's generated C code uses gotos;\n\t\t// Older V versions of the json codegen generated `if(cond) \\nstatement; statement2;` with wrong indentation, instead of blocks;\n\t\t// => Adding the flags below allows v-analyzer to be compiled with -cstrict, and wider range of supported C compilers\n\t\tresulting_cmd += ' -cflags \"-Wno-misleading-indentation -Wno-jump-misses-init -Wno-error=jump-misses-init -Wno-typedef-redefinition\"'\n\t}\n\treturn resulting_cmd\n}\n\nfn prepare_output_dir() string {\n\toutput_dir := './bin'\n\tif os.exists(output_dir) {\n\t\treturn output_dir\n\t}\n\tos.mkdir(output_dir) or { eline('Failed to create output directory: ${err}') }\n\treturn output_dir\n}\n\nfn build(mode ReleaseMode, explicit_debug bool) {\n\todir := prepare_output_dir()\n\tprintln('${gcheck} Prepared output directory `${odir}` .')\n\n\tdetect_build_os()\n\n\tvexe_version := os.execute('${os.quoted_path(vexe)} version').output.trim_space()\n\tprintln('${ynote} Building with ${vexe_version} .')\n\tprintln('${ynote} Building v-analyzer at commit: ${build_commit} .')\n\tprintln('${ynote} Building start time: ${build_datetime} .')\n\n\tcmd := mode.compile_cmd()\n\tprintln('${ynote} Compiling v-analyzer in ${term.bold(mode.str())} mode, using:')\n\tprintln(cmd)\n\tif mode == .release {\n\t\tprintln('This may take 1-2 minutes... Please wait.')\n\t}\n\n\tif !explicit_debug && mode == .debug {\n\t\tprintln('')\n\t\tprintln('Note: to build in ${term.bold('release')} mode, run `${term.bold('v build.vsh release')}` .')\n\t\tprintln('    Release mode is recommended for production use.')\n\t\tprintln('    At runtime, it is about 30-40% faster than debug mode.')\n\t\tprintln('')\n\t}\n\n\tos.execute_opt(cmd) or {\n\t\teline('Failed to build v-analyzer')\n\t\teprintln(err)\n\t\texit(1)\n\t}\n\n\tfinal_path := abs_path(bin_path)\n\tnbytes := os.file_size(final_path)\n\tprintln('${ynote} The binary size in bytes is: ${nbytes:8} .')\n\tprintln('${ynote} The binary is located here: ${term.bold(final_path)} .')\n\telapsed_ms := f64((time.now() - build_time).milliseconds())\n\tprintln('${gcheck} Successfully built v-analyzer, in ${elapsed_ms / 1000.0:5.3f}s .')\n}\n\n// main program:\n\nos.setenv('BUILD_DATETIME', build_datetime, true)\nos.setenv('BUILD_COMMIT', build_commit, true)\n\nmut cmd := cli.Command{\n\tname:        'v-analyzer-builder'\n\tversion:     metadata.manifest.version\n\tdescription: 'Builds the v-analyzer binary.'\n\tposix_mode:  true\n\texecute:     fn (_ cli.Command) ! {\n\t\tbuild(.debug, false)\n\t}\n}\n\n// debug builds the v-analyzer binary in debug mode.\n// This is the default mode.\n// Thanks to -d use_libbacktrace, the binary will print beautiful stack traces,\n// which is very useful for debugging.\ncmd.add_command(cli.Command{\n\tname:        'debug'\n\tdescription: 'Builds the v-analyzer binary in debug mode.'\n\texecute:     fn (_ cli.Command) ! {\n\t\tbuild(.debug, true)\n\t}\n})\n\n// dev builds the v-analyzer binary in development mode.\n// In this mode, additional development features are enabled.\ncmd.add_command(cli.Command{\n\tname:        'dev'\n\tdescription: 'Builds the v-analyzer binary in development mode.'\n\texecute:     fn (_ cli.Command) ! {\n\t\tbuild(.dev, false)\n\t}\n})\n\n// release builds the v-analyzer binary in release mode.\n// This is the recommended mode for production use.\n// It is about 30-40% faster than debug mode.\ncmd.add_command(cli.Command{\n\tname:        'release'\n\tdescription: 'Builds the v-analyzer binary in release mode.'\n\texecute:     fn (_ cli.Command) ! {\n\t\tbuild(.release, false)\n\t}\n})\n\ncmd.parse(os.args)\n"
  },
  {
    "path": "editors/code/.editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = tab\nmax_line_length = 90\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.{yml,yaml}]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": "editors/code/.eslintignore",
    "content": "node_modules/\ndist/\nscripts/\n"
  },
  {
    "path": "editors/code/.eslintrc.json",
    "content": "{\n\t\"root\": true,\n\t\"parser\": \"@typescript-eslint/parser\",\n\t\"parserOptions\": {\n\t\t\"tsconfigRootDir\": \".\",\n\t\t\"project\": [\"./tsconfig.json\"]\n\t},\n\t\"plugins\": [\n\t\t\"@typescript-eslint\"\n\t],\n\t\"extends\": [\n\t\t\"eslint:recommended\",\n\t\t\"plugin:@typescript-eslint/recommended\",\n\t\t\"plugin:@typescript-eslint/recommended-requiring-type-checking\"\n\t],\n\t\"rules\": {\n\t\t\"prefer-const\": \"error\",\n\t\t\"no-array-constructor\": \"error\",\n\t\t\"no-new-object\": \"error\",\n\t\t\"no-shadow\": \"error\",\n\t\t\"no-undef-init\": \"error\",\n\t\t\"no-var\": \"error\",\n\t\t\"object-shorthand\": \"error\",\n\t\t\"prefer-template\": \"error\",\n\t\t// Stylisitc rules\n\t\t\"array-bracket-spacing\": \"error\",\n\t\t\"brace-style\": \"error\",\n\t\t\"block-spacing\": \"error\",\n\t\t\"camelcase\": \"error\",\n\t\t\"comma-spacing\": \"error\",\n\t\t\"eol-last\": \"error\",\n\t\t\"func-call-spacing\": \"error\",\n\t\t\"quotes\": [\"error\", \"single\"],\n\t\t\"semi\": \"error\"\n\t}\n}\n"
  },
  {
    "path": "editors/code/.gitignore",
    "content": ".vscode/ipch\n.idea/\n*.code-workspace\nnode_modules/\ndist/\n*.exe\n*.tmp.json\n*.vsix\n.DS_Store\npackage-lock.json\n"
  },
  {
    "path": "editors/code/.vscodeignore",
    "content": ".vscode/**\n.vscode-test/**\ndocs/\nnode_modules/\nscripts/\nsrc/\nimages/\n**/tests/\n\n**/tslint.json\n**/*.map\n**/*.tmp.json\n.eslintignore\n.gitignore\ntsconfig.json\npackage-lock.json\n"
  },
  {
    "path": "editors/code/CHANGELOG.md",
    "content": "# v-analyzer VS Code Extension Changelog\n\n## [0.0.1] - 03.07.2023\n\nFirst public release.\n\nPlease note that this is a beta version, so it may contain any bugs.\n"
  },
  {
    "path": "editors/code/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 V Open Source Community Association (VOSCA)\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": "editors/code/README.md",
    "content": "# v-analyzer support for Visual Studio Code\n\n[![VSCode Extension](https://img.shields.io/badge/VS_Code-extension-25829e?logo=visualstudiocode&logoWidth=10)](https://marketplace.visualstudio.com/items?itemName=VOSCA.vscode-v-analyzer)\n[![VS Code extension tests](https://github.com/vlang/v-analyzer/actions/workflows/vscode_extension_tests.yml/badge.svg)](https://github.com/vlang/v-analyzer/actions/workflows/vscode_extension_tests.yml)\n\nProvides\n[V programming language](https://vlang.io)\nand\n[`v-analyzer`](https://github.com/vlang/v-analyzer)\nsupport for Visual Studio Code.\nIt is recommended over and replaces\n[V extension](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang).\n\nFor most of its functionality, the extension uses\n[`v-analyzer`](https://github.com/vlang/v-analyzer),\nwhich we will refer to as the server to avoid confusion.\n\n## Features\n\n- syntax highlighting\n- code completion\n- go to definition, type definition\n- find all references, document symbol, symbol renaming\n- types and documentation on hover\n- inlay hints for types and some construction like `or` block\n- semantic syntax highlighting\n- formatting\n- signature help\n\n## Getting started\n\nWelcome! 👋🏻\n\nLet's get started setting up **v-analyzer** in VS Code!\n\n1. First of all, make sure you have the latest version of V installed.\n   If you are unsure, run `v up` to update.\n\n2. Now let's install VS Code **v-analyzer** extension:\n\n    1. Open the command palette with `Ctrl+Shift+P` or `Cmd+Shift+P`\n    2. Select `Install Extensions` and choose `v-analyzer`.\n\n   You can also install the extension manually:\n\n    1. Select `Install from VSIX...`\n    2. Choose pre-built VSIX file from this folder or build it yourself\n\n   After installation, restart VS Code.\n\n3. Open any project that contains files with `.v` extension.\n   The extension should automatically activate.\n   Upon activation, the extension will try to find `v-analyzer` server, which\n   is the heart of the extension and provides all the smart features.\n\n4. Since `v-analyzer` server is not installed\n   (unless you installed it in advance and added it to PATH, in which case you\n   can skip this step), the extension will prompt you to install it.\n   Click `Install` and wait for the installation to complete.\n\n5. After installing `v-analyzer` server, the extension will prompt you to\n   restart the `v-analyzer` server.\n   Click `Yes` and wait for the restart to complete.\n\n6. When `v-analyzer` server is successfully restarted,\n   it will start to analyze your project as well as the V standard library.\n\n7. Note that if `v-analyzer` server cannot find where the V standard library\n   is stored, an error will be shown.\n\n   In this case, follow the instructions in the error and specify the path to\n   the V source code folder in the `custom_vroot` field.\n\n   > **Note**\n   > You need to specify the folder where all the V sources are stored\n   > (e.g. `C:\\v\\` or `/home/user/v/` and not the folder with the standard library\n   > (e.g. `C:\\v\\vlib` or `/home/user/v/vlib`)!\n   > After making changes, restart `v-analyzer` using the `v-analyzer: Restart server`\n   > command in the command palette.\n\n8. If the server was able to find all the necessary things, then after a while the\n   indexing will end, and you will be able to use all the features of `v-analyzer`.\n\n   > **Note**\n   > Indexing can take up to 30 seconds on weak machines, but this is only\n   > done on the first run; then the indexes will be loaded from the cache.\n\nYou are ready to code in V! 🎉\n\n## Manual Setup\n\nYou can install ``v-analyzer`` server manually:\nClone the\n[`v-analyzer`](https://github.com/vlang/v-analyzer)\nrepository, build it and specify the path to the compiled binary.\n\n```json\n{\n    \"v-analyzer.serverPath\": \"path/to/v-analyzer\"\n}\n```\n\n## Auto save\n\n`v-analyzer` uses `v` compiler to analyze code.\nIt calls it every time a file is saved, so you can set up auto-save to get real-time\nfeedback.\n\n```json\n{\n    \"files.autoSave\": \"afterDelay\",\n    \"files.autoSaveDelay\": 300\n}\n```\n\n## Semantic tokens\n\nWith highlighting based on TextMate grammar, v-analyzer provides semantic\nhighlighting, which allows you to highlight fields, variables, parameters and other\nelements as different entities.\n\nTo enable semantic highlighting, make sure the `editor.semanticHighlighting.enabled`\nsetting is set to `true` in the VS Code settings.\n\nIn the settings, you can also specify colors for each entity type:\n\n```json\n{\n    \"editor.semanticTokenColorCustomizations\": {\n        \"[Theme Name]\": {\n            \"rules\": {\n                \"namespace\": \"#AFBF7E\",\n                \"parameter\": \"#B189F5\",\n                \"decorator\": \"#DEBC7E\",\n                \"typeParameter\": \"#B189F5\",\n                \"enumMember\": \"#72CFD6\",\n                \"*.global\": \"#A9B7C6\",\n                \"function\": \"#FFC66D\",\n                \"*.mutable\": {\n                    \"underline\": true\n                }\n            }\n        }\n    }\n}\n```\n\nSee\n[all available entity types](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#semanticTokenTypes)\nin the LSP specification.\n\n## Building from source\n\n```bash\nnpm install\nnpm run package\n```\n\n## License\n\nThis project is under the **MIT License**.\nSee the\n[LICENSE](https://github.com/vlang/v-analyzer/blob/main/editors/code/LICENSE)\nfile for the full license text.\n"
  },
  {
    "path": "editors/code/docs/troubleshooting.md",
    "content": "# Troubleshooting\n\nIf you suspect that the V extension is not working correctly, please follow the\ntroubleshooting steps below.\n\nTODO\n"
  },
  {
    "path": "editors/code/languages/v-language-configuration.json",
    "content": "{\n\t\"comments\": {\n\t\t\"lineComment\": \"//\",\n\t\t\"blockComment\": [\"/*\", \"*/\"]\n\t},\n\t\"folding\": {\n\t\t\"markers\": {\n\t\t\t\"start\": \"^\\\\s*//\\\\s*#?region\\\\b\",\n\t\t\t\"end\": \"^\\\\s*//\\\\s*#?endregion\\\\b\"\n\t\t}\n\t},\n\t\"brackets\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"]\n\t],\n\t\"autoClosingPairs\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"],\n\t\t[\"\\\"\", \"\\\"\"],\n\t\t[\"'\", \"'\"]\n\t],\n\t\"surroundingPairs\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"],\n\t\t[\"\\\"\", \"\\\"\"],\n\t\t[\"'\", \"'\"]\n\t]\n}\n"
  },
  {
    "path": "editors/code/languages/vmod-language-configuration.json",
    "content": "{\n\t\"comments\": {\n\t\t\"lineComment\": \"//\",\n\t\t\"blockComment\": [\"/*\", \"*/\"]\n\t},\n\t\"folding\": {\n\t\t\"markers\": {\n\t\t\t\"start\": \"^\\\\s*//\\\\s*#?region\\\\b\",\n\t\t\t\"end\": \"^\\\\s*//\\\\s*#?endregion\\\\b\"\n\t\t}\n\t},\n\t\"brackets\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"]\n\t],\n\t\"autoClosingPairs\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"],\n\t\t[\"\\\"\", \"\\\"\"],\n\t\t[\"'\", \"'\"]\n\t],\n\t\"surroundingPairs\": [\n\t\t[\"{\", \"}\"],\n\t\t[\"[\", \"]\"],\n\t\t[\"(\", \")\"],\n\t\t[\"\\\"\", \"\\\"\"],\n\t\t[\"'\", \"'\"]\n\t]\n}\n"
  },
  {
    "path": "editors/code/media/welcome.css",
    "content": "/*---------------------------------------------------------\n * Copyright 2020 The Go Authors. All rights reserved.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n *--------------------------------------------------------*/\n\n.Content {\n\tmax-width: 60rem;\n\tfont-size: 1rem;\n\tline-height: 1.5rem;\n\tmargin: auto;\n}\n\n.Header {\n\talign-items: center;\n\tdisplay: flex;\n\tborder-bottom: 0.0625rem solid #ccc;\n\tmargin-bottom: 2rem;\n\tpadding-bottom: 1.25rem;\n}\n\n.Header-logo {\n\twidth: 12rem;\n\tmargin-right: 3rem;\n}\n\n.Header-title {\n\tfont-size: 1.75rem;\n}\n\n.Announcement {\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: center;\n\tfont-style: italic;\n\tpadding: 1rem;\n}\n\n.Announcement-image {\n\theight: 2rem;\n\tflex: 0;\n\tmargin-right: 1.5rem;\n}\n\n.Cards {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex-wrap: wrap;\n}\n\n.Card {\n\tmax-width: 40rem;\n\tflex: 1;\n}\n\n.Card-inner {\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tpadding: 0rem;\n}\n\n.Card-title {\n\tfont-size: 1.5rem;\n\tfont-weight: 500;\n}\n\n.Card-content {\n\tmargin: 0;\n}\n\na:link,\na:visited {\n\ttext-decoration: none;\n}\n\n.Command:hover,\na:hover {\n\ttext-decoration: underline;\n}\n\n@media (min-width: 40rem) {\n\t.Header-links {\n\t\tlist-style: none;\n\t\tpadding: 0;\n\t}\n\n\t.Header-links li {\n\t\tfloat: left;\n\t}\n\n\t.Header-links li:not(:first-child):before {\n\t\tcontent: \"|\";\n\t\tcolor: #ccc;\n\t\tpadding: 0 1rem;\n\t}\n\n\t.Cards {\n\t\tflex-direction: row;\n\t\tjustify-content: space-between;\n\t}\n\n\t.Card:not(:last-child) {\n\t\tmargin-right: 4rem;\n\t}\n}\n"
  },
  {
    "path": "editors/code/package.json",
    "content": "{\n\t\"name\": \"vscode-v-analyzer\",\n\t\"displayName\": \"v-analyzer\",\n\t\"description\": \"V language support (syntax highlighting, formatter, language server) for Visual Studio Code.\",\n\t\"publisher\": \"VOSCA\",\n\t\"icon\": \"icons/icon.png\",\n\t\"version\": \"0.0.6\",\n\t\"engines\": {\n\t\t\"vscode\": \"^1.66.0\"\n\t},\n\t\"homepage\": \"https://github.com/vlang/v-analyzer\",\n\t\"license\": \"MIT\",\n\t\"bugs\": {\n\t\t\"url\": \"https://github.com/vlang/v-analyzer/issues\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"https://github.com/vlang/v-analyzer\"\n\t},\n\t\"keywords\": [\n\t\t\"V\",\n\t\t\"v\",\n\t\t\"v language\",\n\t\t\"vlang\"\n\t],\n\t\"scripts\": {\n\t\t\"compile\": \"node ./scripts/build.js\",\n\t\t\"compile-dev\": \"node ./scripts/build.js --dev\",\n\t\t\"compile-watch\": \"node ./scripts/build.js --watch\",\n\t\t\"test\": \"npm run testgrammar\",\n\t\t\"lint\": \"eslint .\",\n\t\t\"lintmd\": \"markdownlint *.md -i CHANGELOG.md\",\n\t\t\"vscode:prepublish\": \"node ./scripts/minify_json.js && npm run compile\",\n\t\t\"watch\": \"tsc -watch -p ./\",\n\t\t\"package\": \"npx vsce package\",\n\t\t\"postpackage\": \"node ./scripts/minify_json.js --restore\",\n\t\t\"testgrammar\": \"vscode-tmgrammar-test -g syntaxes/v.tmLanguage.json \\\"syntaxes/tests/*.vv\\\"\",\n\t\t\"format\": \"prettier --write \\\"scripts/**/*.js\\\" \\\"src/**/*.ts\\\"\"\n\t},\n\t\"main\": \"dist/extension.js\",\n\t\"dependencies\": {\n\t\t\"axios\": \"^1.6.8\",\n\t\t\"semver\": \"^7.6.0\",\n\t\t\"vscode-languageclient\": \"^9.0.1\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/node\": \"^20.11.28\",\n\t\t\"@types/semver\": \"^7.5.8\",\n\t\t\"@types/vscode\": \"~1.66.0\",\n\t\t\"@typescript-eslint/eslint-plugin\": \"^7.2.0\",\n\t\t\"@typescript-eslint/parser\": \"^7.2.0\",\n\t\t\"@vscode/vsce\": \"^2.24.0\",\n\t\t\"esbuild\": \"^0.20.2\",\n\t\t\"eslint\": \"^8.57.0\",\n\t\t\"markdownlint-cli\": \"^0.39.0\",\n\t\t\"prettier\": \"^3.2.5\",\n\t\t\"typescript\": \"^5.4.2\",\n\t\t\"vscode-tmgrammar-test\": \"^0.1.3\"\n\t},\n\t\"activationEvents\": [\n\t\t\"workspaceContains:**/*.v\",\n\t\t\"workspaceContains:**/*.vv\",\n\t\t\"workspaceContains:**/*.vsh\",\n\t\t\"workspaceContains:**/v.mod\",\n\t\t\"onCommand:v.runWorkspace\",\n\t\t\"onCommand:v.runFile\",\n\t\t\"onCommand:v.runTests\",\n\t\t\"onCommand:v.version\",\n\t\t\"onCommand:v.serverVersion\"\n\t],\n\t\"categories\": [\n\t\t\"Programming Languages\"\n\t],\n\t\"extensionPack\": [\n\t\t\"ms-vscode.cpptools\"\n\t],\n\t\"contributes\": {\n\t\t\"languages\": [\n\t\t\t{\n\t\t\t\t\"id\": \"v\",\n\t\t\t\t\"aliases\": [\n\t\t\t\t\t\"V\"\n\t\t\t\t],\n\t\t\t\t\"extensions\": [\n\t\t\t\t\t\".v\",\n\t\t\t\t\t\".vsh\",\n\t\t\t\t\t\".vv\"\n\t\t\t\t],\n\t\t\t\t\"configuration\": \"languages/v-language-configuration.json\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"v.mod\",\n\t\t\t\t\"language\": \"v.mod\",\n\t\t\t\t\"scopeName\": \"source.v.mod\",\n\t\t\t\t\"extensions\": [\n\t\t\t\t\t\".mod\"\n\t\t\t\t],\n\t\t\t\t\"configuration\": \"languages/vmod-language-configuration.json\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"stree\",\n\t\t\t\t\"scopeName\": \"source.stree\",\n\t\t\t\t\"extensions\": [\n\t\t\t\t\t\".stree\"\n\t\t\t\t]\n\t\t\t}\n\t\t],\n\t\t\"grammars\": [\n\t\t\t{\n\t\t\t\t\"language\": \"v\",\n\t\t\t\t\"scopeName\": \"source.v\",\n\t\t\t\t\"path\": \"syntaxes/v.tmLanguage.json\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"language\": \"v.mod\",\n\t\t\t\t\"scopeName\": \"source.v.mod\",\n\t\t\t\t\"path\": \"syntaxes/v.mod.tmLanguage.json\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"language\": \"stree\",\n\t\t\t\t\"scopeName\": \"source.stree\",\n\t\t\t\t\"path\": \"syntaxes/stree.tmGrammar.json\"\n\t\t\t}\n\t\t],\n\t\t\"configuration\": {\n\t\t\t\"title\": \"v-analyzer\",\n\t\t\t\"properties\": {\n\t\t\t\t\"v.executablePath\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"description\": \"Custom path to the V compiler executable (`v`).\\nNOTE: Setting this won't change the VROOT path in v-analyzer.\"\n\t\t\t\t},\n\t\t\t\t\"v-analyzer.customVrootPath\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"default\": \"\",\n\t\t\t\t\t\"description\": \"Custom path to the V installation directory (VROOT).\\nNOTE: Setting this won't change the V compiler executable to be used.\"\n\t\t\t\t},\n\t\t\t\t\"v-analyzer.serverPath\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"default\": \"\",\n\t\t\t\t\t\"description\": \"Custom path to the v-analyzer executable (if empty uses `v-analyzer` executable from PATH).\"\n\t\t\t\t},\n\t\t\t\t\"v-analyzer.connectionMode\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"default\": \"stdio\",\n\t\t\t\t\t\"enum\": [\n\t\t\t\t\t\t\"stdio\",\n\t\t\t\t\t\t\"tcp\"\n\t\t\t\t\t],\n\t\t\t\t\t\"description\": \"Specify the mode to be used when connecting to v-analyzer.\",\n\t\t\t\t\t\"enumDescriptions\": [\n\t\t\t\t\t\t\"Connects to the language server via standard input/output. (Default)\",\n\t\t\t\t\t\t\"Connects to the language server via TCP (you need to run analyzer manually with `--socket` flag, debug only!).\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"v-analyzer.tcpMode.port\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\"default\": 5007,\n\t\t\t\t\t\"description\": \"Port to be used when connecting to the language server. (Only in TCP mode)\"\n\t\t\t\t},\n\t\t\t\t\"v-analyzer.customArgs\": {\n\t\t\t\t\t\"scope\": \"resource\",\n\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\"description\": \"Custom arguments to be passed to the v-analyzer executable.\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"configurationDefaults\": {\n\t\t\t\"[v]\": {\n\t\t\t\t\"editor.insertSpaces\": false\n\t\t\t}\n\t\t},\n\t\t\"keybindings\": [\n\t\t\t{\n\t\t\t\t\"command\": \"v.fmt\",\n\t\t\t\t\"key\": \"ctrl+i ctrl+i\"\n\t\t\t}\n\t\t],\n\t\t\"commands\": [\n\t\t\t{\n\t\t\t\t\"command\": \"v.run\",\n\t\t\t\t\"title\": \"Run current directory\",\n\t\t\t\t\"category\": \"V\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v.fmt\",\n\t\t\t\t\"title\": \"Format current file\",\n\t\t\t\t\"category\": \"V\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v.prod\",\n\t\t\t\t\"title\": \"Build an optimized executable from current file\",\n\t\t\t\t\"category\": \"V\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.version\",\n\t\t\t\t\"title\": \"Show language version\",\n\t\t\t\t\"category\": \"V\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.serverVersion\",\n\t\t\t\t\"title\": \"Show v-analyzer server version\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.startServer\",\n\t\t\t\t\"title\": \"Start server\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.stopServer\",\n\t\t\t\t\"title\": \"Stop server\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.restartServer\",\n\t\t\t\t\"title\": \"Restart server\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.showReferences\",\n\t\t\t\t\"title\": \"Show References\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.viewStubTree\",\n\t\t\t\t\"title\": \"View Stub Tree\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.uploadToPlayground\",\n\t\t\t\t\"title\": \"Upload to V Playground\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.showWelcome\",\n\t\t\t\t\"title\": \"Show Welcome\",\n\t\t\t\t\"description\": \"Open the welcome page for the v-analyzer extension.\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"command\": \"v-analyzer.openGlobalConfig\",\n\t\t\t\t\"title\": \"Open Global Config\",\n\t\t\t\t\"description\": \"Open the global config file for the v-analyzer server.\",\n\t\t\t\t\"category\": \"v-analyzer\"\n\t\t\t}\n\t\t],\n\t\t\"menus\": {\n\t\t\t\"commandPalette\": [\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v.run\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v.fmt\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v.prod\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v-analyzer.serverVersion\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v-analyzer.stopServer\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v-analyzer.restartServer\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"command\": \"v-analyzer.uploadToPlayground\",\n\t\t\t\t\t\"when\": \"inVlangProject\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"breakpoints\": [\n\t\t\t{\n\t\t\t\t\"language\": \"v\"\n\t\t\t}\n\t\t],\n\t\t\"semanticTokenModifiers\": [\n\t\t\t{\n\t\t\t\t\"id\": \"mutable\",\n\t\t\t\t\"description\": \"Style for mutable variables/parameters/receivers\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"global\",\n\t\t\t\t\"description\": \"Style for global variables\"\n\t\t\t}\n\t\t],\n\t\t\"semanticTokenScopes\": [\n\t\t\t{\n\t\t\t\t\"language\": \"v\",\n\t\t\t\t\"scopes\": {\n\t\t\t\t\t\"*.mutable\": [\n\t\t\t\t\t\t\"markup.underline\"\n\t\t\t\t\t],\n\t\t\t\t\t\"*.global\": [\n\t\t\t\t\t\t\"markup.bold\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "editors/code/scripts/build.js",
    "content": "#!/usr/bin/env node\n//@ts-check\n\"use strict\";\n\nconst esbuild = require(\"esbuild\");\n\nconst isWatch = process.argv.includes(\"--watch\");\nconst isDev = process.argv.includes(\"--dev\");\n\nesbuild\n\t.context({\n\t\tplatform: \"node\",\n\t\tentryPoints: [\"./src/extension.ts\"],\n\t\toutdir: \"./dist\",\n\t\texternal: [\"vscode\"],\n\t\tformat: \"cjs\",\n\t\tsourcemap: \"external\",\n\t\tbundle: true,\n\t\tminify: !isDev,\n\t})\n\t.then((context) => {\n\t\tif (isWatch) {\n\t\t\tcontext.watch();\n\t\t} else {\n\t\t\tcontext.rebuild().then(() => context.dispose());\n\t\t}\n\t})\n\t.catch(() => process.exit(1));\n"
  },
  {
    "path": "editors/code/scripts/minify_json.js",
    "content": "#!/usr/bin/env node\n// @ts-check\n\"use strict\";\n\nconst { exec } = require(\"child_process\");\nconst { writeFileSync, copyFileSync, renameSync, existsSync } = require(\"fs\");\nconst { resolve } = require(\"path\");\n\nconst jsonFiles = [\n\t\"../syntaxes/v.tmLanguage.json\",\n\t\"../syntaxes/v.mod.tmLanguage.json\",\n\t\"../languages/v-language-configuration.json\",\n\t\"../languages/vmod-language-configuration.json\",\n];\n\nconst shouldRestore = process.argv.includes(\"--restore\");\njsonFiles.forEach((jsonFile) => {\n\tconst absolutePath = resolve(__dirname, jsonFile);\n\tconst tmpFile = resolve(__dirname, jsonFile.replace(\".json\", \".tmp.json\"));\n\tif (shouldRestore) {\n\t\trenameSync(tmpFile, absolutePath);\n\t} else {\n\t\tif (!existsSync(tmpFile)) {\n\t\t\tcopyFileSync(absolutePath, tmpFile);\n\t\t}\n\t\texec(`npx json-minify ${absolutePath}`, (error, stdout) => {\n\t\t\tif (error) throw error;\n\t\t\twriteFileSync(absolutePath, stdout);\n\t\t});\n\t}\n});\n"
  },
  {
    "path": "editors/code/src/bootstrap.ts",
    "content": "import cp from \"child_process\";\nimport os from \"os\";\nimport fs from \"fs\";\nimport { log } from \"./log\";\nimport { getWorkspaceConfig } from \"./utils\";\nimport { AnalyzerNotInstalledError } from \"./ctx\";\n\n/**\n * bootstrap returns the path to the v-analyzer binary.\n * It will throw an error if the binary is not available.\n *\n * @returns {Promise<string>} The path to the v-analyzer binary.\n */\nexport async function bootstrap(): Promise<string> {\n\tconst path = getAnalyzerPath();\n\n\tif (!isAnalyzerExecutableValid(path)) {\n\t\tconst config = getWorkspaceConfig();\n\t\tconst explicitPath = config.get<string>(\"serverPath\");\n\t\tif (explicitPath) {\n\t\t\tthrow new Error(`Failed to execute ${path} -v. \\`config.serverPath\\`has been set explicitly.\\\n            Consider removing this config or making a valid server binary available at that path.`);\n\t\t}\n\n\t\tthrow new AnalyzerNotInstalledError(\n\t\t\t`Failed to execute ${path} -v, make sure the v-analyzer is installed and available in the PATH`,\n\t\t);\n\t}\n\n\tlog.info(\"Server binary path:\", path);\n\n\treturn path;\n}\n\nfunction getAnalyzerPath(): string {\n\tconst config = getWorkspaceConfig();\n\tconst explicitPath = config.get<string>(\"serverPath\");\n\tconst path = explicitPath ? explicitPath : \"v-analyzer\";\n\n\tif (path.startsWith(\"~/\") || path.startsWith(\"~\\\\\")) {\n\t\treturn path.replace(\"~\", os.homedir());\n\t}\n\n\treturn path;\n}\n\nfunction isAnalyzerExecutableValid(path: string): boolean {\n\tconst location = path === \"v-analyzer\" ? \"PATH\" : path;\n\tlog.debug(\"Checking availability of a binary at\", location);\n\tconst res = cp.spawnSync(`${path}`, [\"-v\"]);\n\treturn res.status === 0;\n}\n"
  },
  {
    "path": "editors/code/src/client.ts",
    "content": "import * as lc from \"vscode-languageclient/node\";\nimport vscode, { window, workspace } from \"vscode\";\n\nlet crashCount = 0;\n\nexport async function createClient(\n\toutputChannel: vscode.OutputChannel,\n\tserverOptions: lc.ServerOptions,\n): Promise<lc.LanguageClient> {\n\tconst clientOptions: lc.LanguageClientOptions = {\n\t\tdocumentSelector: [{ scheme: \"file\", language: \"v\" }],\n\t\tsynchronize: {\n\t\t\tfileEvents: workspace.createFileSystemWatcher(\"**/*.v\"),\n\t\t},\n\t\toutputChannel: outputChannel,\n\t\terrorHandler: {\n\t\t\terror: (error: Error, _: lc.Message, count: number) => {\n\t\t\t\t// taken from: https://github.com/golang/vscode-go/blob/HEAD/src/goLanguageServer.ts#L533-L539\n\t\t\t\tif (count < 5) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: \"\", // suppresses error popups\n\t\t\t\t\t\taction: lc.ErrorAction.Continue,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tvoid window.showErrorMessage(\n\t\t\t\t\t`v-analyzer: Error communicating with the language server: ${error}: ${error}.`,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\taction: lc.ErrorAction.Shutdown,\n\t\t\t\t};\n\t\t\t},\n\t\t\tclosed: () => {\n\t\t\t\tcrashCount++;\n\t\t\t\tif (crashCount < 5) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: \"\", // suppresses error popups\n\t\t\t\t\t\taction: lc.CloseAction.Restart,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\taction: lc.CloseAction.DoNotRestart,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t\tmarkdown: {\n\t\t\tisTrusted: true,\n\t\t\tsupportHtml: true,\n\t\t},\n\t};\n\n\tconst client = new lc.LanguageClient(\n\t\t\"v-analyzer\",\n\t\t\"V Language Server\",\n\t\tserverOptions,\n\t\tclientOptions,\n\t\ttrue,\n\t);\n\n\tclient.registerFeature(new ExperimentalFeatures());\n\n\treturn client;\n}\n\nclass ExperimentalFeatures implements lc.StaticFeature {\n\tfillInitializeParams?: (params: lc.InitializeParams) => void;\n\tpreInitialize?: (\n\t\tcapabilities: lc.ServerCapabilities<any>,\n\t\tdocumentSelector: lc.DocumentSelector,\n\t) => void;\n\tclear(): void {}\n\tgetState(): lc.FeatureState {\n\t\treturn { kind: \"static\" };\n\t}\n\n\tfillClientCapabilities(capabilities: lc.ClientCapabilities): void {\n\t\tcapabilities.experimental = {\n\t\t\tserverStatusNotification: true,\n\t\t\tviewStubTree: true,\n\t\t\t...capabilities.experimental,\n\t\t};\n\t}\n\n\tinitialize(\n\t\t_capabilities: lc.ServerCapabilities,\n\t\t_documentSelector: lc.DocumentSelector | undefined,\n\t): void {}\n\n\tdispose(): void {}\n}\n"
  },
  {
    "path": "editors/code/src/commands.ts",
    "content": "import * as vscode from \"vscode\";\nimport * as path from \"path\";\nimport * as lc from \"vscode-languageclient\";\nimport * as ra from \"./lsp_ext\";\nimport * as os from \"os\";\nimport { runVCommand, runVCommandCallback } from \"./exec\";\nimport { Command, ContextInit } from \"./ctx\";\nimport { LanguageClient } from \"vscode-languageclient/node\";\nimport { spawnSync } from \"child_process\";\nimport { isVlangDocument, isVlangEditor, sleep } from \"./utils\";\nimport { log } from \"./log\";\nimport axios from \"axios\";\nimport FormData from \"form-data\";\n\n/**\n * Run current directory.\n */\nexport function runWorkspace(_: ContextInit): Command {\n\treturn async () => {\n\t\tconst document = vscode.window.activeTextEditor.document;\n\t\tawait document.save();\n\t\tconst dir = path.parse(document.fileName).dir;\n\n\t\trunVCommand([\"run\", dir]);\n\t};\n}\n\nexport function runFile(_: ContextInit): Command {\n\treturn async () => {\n\t\tconst document = vscode.window.activeTextEditor.document;\n\t\tawait document.save();\n\t\tconst fileName = document.fileName;\n\n\t\trunVCommand([\"run\", fileName]);\n\t};\n}\n\nexport function runTests(_: ContextInit): Command {\n\treturn async (uri: string, name?: string) => {\n\t\tconst args = [\"test\", uri];\n\t\tif (name) {\n\t\t\targs.push(\"-run-only\", `\"*.${name}\"`);\n\t\t}\n\t\trunVCommand(args);\n\t};\n}\n\n/**\n * Show version info.\n */\nexport function version(_: ContextInit): Command {\n\treturn () => {\n\t\trunVCommandCallback([\"-version\"], (err, stdout) => {\n\t\t\tif (err) {\n\t\t\t\tvoid vscode.window.showErrorMessage(\n\t\t\t\t\t\"Unable to get the version number. Is V installed correctly?\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvoid vscode.window.showInformationMessage(stdout);\n\t\t});\n\t};\n}\n\nexport function serverVersion(ctx: ContextInit): Command {\n\treturn async () => {\n\t\tif (!ctx.serverPath) {\n\t\t\tvoid vscode.window.showWarningMessage(`v-analyzer server is not running`);\n\t\t\treturn;\n\t\t}\n\t\tconst { stdout } = spawnSync(ctx.serverPath, [\"--version\"], { encoding: \"utf8\" });\n\t\tconst versionString = stdout.slice(`v-analyzer version`.length).trim();\n\n\t\tvoid vscode.window.showInformationMessage(`v-analyzer version: ${versionString}`);\n\t};\n}\n\nexport function showReferences(ctx: ContextInit): Command {\n\treturn async (uri: string, positionData: string, locationData: string) => {\n\t\tconst locations = JSON.parse(locationData);\n\t\tconst position = JSON.parse(positionData);\n\t\tawait showReferencesImpl(ctx.client, uri, position, locations);\n\t};\n}\n\nexport async function showReferencesImpl(\n\tclient: LanguageClient | undefined,\n\turi: string,\n\tposition: lc.Position,\n\tlocations: lc.Location[],\n) {\n\tif (!client) return;\n\tawait vscode.commands.executeCommand(\n\t\t\"editor.action.showReferences\",\n\t\tvscode.Uri.parse(uri),\n\t\tclient.protocol2CodeConverter.asPosition(position),\n\t\tlocations.map(client.protocol2CodeConverter.asLocation),\n\t);\n}\n\nexport function viewStubTree(ctx: ContextInit): Command {\n\tconst tdcp = new (class implements vscode.TextDocumentContentProvider {\n\t\treadonly uri = vscode.Uri.parse(\n\t\t\t\"v-analyzer-file-stub-tree://viewStubTree/file.stree\",\n\t\t);\n\t\treadonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();\n\n\t\tconstructor() {\n\t\t\tvscode.workspace.onDidChangeTextDocument(\n\t\t\t\tthis.onDidChangeTextDocument,\n\t\t\t\tthis,\n\t\t\t\tctx.subscriptions,\n\t\t\t);\n\t\t\tvscode.window.onDidChangeActiveTextEditor(\n\t\t\t\tthis.onDidChangeActiveTextEditor,\n\t\t\t\tthis,\n\t\t\t\tctx.subscriptions,\n\t\t\t);\n\t\t}\n\n\t\tprivate onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {\n\t\t\tif (isVlangDocument(event.document)) {\n\t\t\t\t// We need to order this after language server updates, but there's no API for that.\n\t\t\t\t// Hence, good old sleep().\n\t\t\t\tvoid sleep(10).then(() => this.eventEmitter.fire(this.uri));\n\t\t\t}\n\t\t}\n\n\t\tprivate onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {\n\t\t\tif (editor && isVlangEditor(editor)) {\n\t\t\t\tthis.eventEmitter.fire(this.uri);\n\t\t\t}\n\t\t}\n\n\t\tasync provideTextDocumentContent(\n\t\t\t_uri: vscode.Uri,\n\t\t\tct: vscode.CancellationToken,\n\t\t): Promise<string> {\n\t\t\tconst rustEditor = ctx.activeVlangEditor;\n\t\t\tif (!rustEditor) return \"\";\n\t\t\tconst client = ctx.client;\n\n\t\t\tconst params = client.code2ProtocolConverter.asTextDocumentIdentifier(\n\t\t\t\trustEditor.document,\n\t\t\t);\n\t\t\treturn client.sendRequest(ra.viewStubTree, params, ct);\n\t\t}\n\n\t\tget onDidChange(): vscode.Event<vscode.Uri> {\n\t\t\treturn this.eventEmitter.event;\n\t\t}\n\t})();\n\n\tctx.pushExtCleanup(\n\t\tvscode.workspace.registerTextDocumentContentProvider(\n\t\t\t\"v-analyzer-file-stub-tree\",\n\t\t\ttdcp,\n\t\t),\n\t);\n\n\treturn async () => {\n\t\tconst document = await vscode.workspace.openTextDocument(tdcp.uri);\n\t\ttdcp.eventEmitter.fire(tdcp.uri);\n\t\tvoid (await vscode.window.showTextDocument(document, {\n\t\t\tviewColumn: vscode.ViewColumn.Two,\n\t\t\tpreserveFocus: true,\n\t\t}));\n\t};\n}\n\nexport function uploadToPlayground(_: ContextInit): Command {\n\treturn async () => {\n\t\tconst editor = vscode.window.activeTextEditor;\n\t\tif (!editor) {\n\t\t\tvscode.window.showInformationMessage(\"No editor is active.\");\n\t\t\treturn;\n\t\t}\n\n\t\tlog.info(\"Uploading to playground...\");\n\n\t\tconst selection = editor.selection;\n\t\tconst code = selection.isEmpty\n\t\t\t? editor.document.getText()\n\t\t\t: editor.document.getText(selection);\n\n\t\tconst form = new FormData();\n\t\tform.append(\"code\", code);\n\n\t\tconst response = await axios.post(\"https://play.vlang.io/share\", form);\n\n\t\tconst json = await response.data;\n\t\tconst hash = json[\"hash\"];\n\t\tconst error = json[\"error\"];\n\n\t\tif (error) {\n\t\t\tvscode.window.showErrorMessage(`V Playground: ${error}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = `https://play.vlang.io/p/${hash}`;\n\n\t\tconst open = await vscode.window.showInformationMessage(\n\t\t\t\"Successfully uploaded to V playground. Open in browser?\",\n\t\t\t\"Open\",\n\t\t\t\"Copy URL\",\n\t\t);\n\t\tif (open === \"Open\") {\n\t\t\tvscode.env.openExternal(vscode.Uri.parse(url));\n\t\t} else if (open === \"Copy URL\") {\n\t\t\tvscode.env.clipboard.writeText(url);\n\t\t}\n\t};\n}\n\nexport function openGlobalConfig(_: ContextInit): Command {\n\treturn async () => {\n\t\tconst configPath = \"~/.config/v-analyzer/config.toml\";\n\t\tconst home = os.homedir();\n\t\tconst configPathWithHome = configPath.replace(\"~\", home);\n\t\tconst uri = vscode.Uri.file(configPathWithHome);\n\t\tconst doc = await vscode.workspace.openTextDocument(uri);\n\t\tawait vscode.window.showTextDocument(doc);\n\t};\n}\n"
  },
  {
    "path": "editors/code/src/ctx.ts",
    "content": "import * as lc from \"vscode-languageclient/node\";\nimport * as ra from \"./lsp_ext\";\nimport * as vscode from \"vscode\";\nimport * as fs from \"fs\";\nimport * as https from \"https\";\nimport * as path from \"path\";\nimport * as cp from \"child_process\";\nimport {\n\tgetWorkspaceConfig,\n\tgetWorkspaceFolder,\n\tisVlangDocument,\n\tisVlangEditor,\n\tVlangEditor,\n} from \"./utils\";\nimport { Progress } from \"vscode\";\nimport { createClient } from \"./client\";\nimport { bootstrap } from \"./bootstrap\";\nimport { connectAnalyzerViaTcp } from \"./tcp\";\nimport { log } from \"./log\";\nimport { runVCommandCallback } from \"./exec\";\n\n// Most of the file taken from `rust-analyzer/editors/code/src/ctx.ts` <3\n\nexport type Workspace =\n\t| { kind: \"Empty\" }\n\t| { kind: \"Workspace Folder\" }\n\t| { kind: \"Detached Files\"; files: vscode.TextDocument[] };\n\nexport function fetchWorkspace(): Workspace {\n\tconst folders = (vscode.workspace.workspaceFolders || []).filter(\n\t\t(folder) => folder.uri.scheme === \"file\",\n\t);\n\tconst vlangDocuments = vscode.workspace.textDocuments.filter((document) =>\n\t\tisVlangDocument(document),\n\t);\n\n\tif (folders.length !== 0) {\n\t\treturn { kind: \"Workspace Folder\" };\n\t}\n\n\tif (vlangDocuments.length === 0) {\n\t\treturn { kind: \"Empty\" };\n\t}\n\n\treturn { kind: \"Detached Files\", files: vlangDocuments };\n}\n\nexport type Command = (...args: any[]) => unknown;\n\nexport type CommandFactory = {\n\tenabled: (ctx: ContextInit) => Command;\n\tdisabled?: (ctx: Context) => Command;\n};\n\nexport type ContextInit = Context & {\n\treadonly client: lc.LanguageClient;\n};\n\nexport class AnalyzerNotInstalledError implements Error {\n\tconstructor(additionalMessage?: string) {\n\t\tthis.message = \"v-analyzer is not installed\";\n\t\tif (additionalMessage) {\n\t\t\tthis.message += `: ${additionalMessage}`;\n\t\t}\n\t\tthis.name = \"AnalyzerNotInstalled\";\n\t}\n\n\tmessage: string;\n\tname: string;\n}\n\nexport class Context {\n\treadonly statusBar: vscode.StatusBarItem;\n\treadonly langStatusBar: vscode.StatusBarItem;\n\tprivate _client: lc.LanguageClient | undefined;\n\tprivate _serverPath: string | undefined;\n\tprivate outputChannel: vscode.OutputChannel | undefined;\n\tprivate clientSubscriptions: Disposable[];\n\tprivate commandDisposables: Disposable[];\n\n\tget client() {\n\t\treturn this._client;\n\t}\n\n\tget subscriptions(): Disposable[] {\n\t\treturn this.extCtx.subscriptions;\n\t}\n\n\tget serverPath(): string | undefined {\n\t\treturn this._serverPath;\n\t}\n\n\tget activeVlangEditor(): VlangEditor | undefined {\n\t\tconst editor = vscode.window.activeTextEditor;\n\t\treturn editor && isVlangEditor(editor) ? editor : undefined;\n\t}\n\n\tconstructor(\n\t\treadonly extCtx: vscode.ExtensionContext,\n\t\treadonly commandFactories: Record<string, CommandFactory>,\n\t\treadonly workspace: Workspace,\n\t) {\n\t\textCtx.subscriptions.push(this);\n\n\t\tthis.statusBar = vscode.window.createStatusBarItem(\n\t\t\t\"v-analyzer-status\",\n\t\t\tvscode.StatusBarAlignment.Left,\n\t\t\t50,\n\t\t);\n\t\tthis.langStatusBar = vscode.window.createStatusBarItem(\n\t\t\t\"v-version\",\n\t\t\tvscode.StatusBarAlignment.Left,\n\t\t\t60,\n\t\t);\n\n\t\tthis.clientSubscriptions = [];\n\t\tthis.commandDisposables = [];\n\n\t\tthis.showLanguageStatusBar();\n\t\tthis.updateCommands(\"disable\");\n\t\tthis.setServerStatus({\n\t\t\thealth: \"stopped\",\n\t\t});\n\t}\n\n\tdispose() {\n\t\tthis.statusBar.dispose();\n\t\tthis.langStatusBar.dispose();\n\t\tvoid this.disposeClient();\n\t\tthis.commandDisposables.forEach((disposable) => disposable.dispose());\n\t}\n\n\tasync start() {\n\t\tlog.info(\"Starting language client\");\n\t\tconst client = await this.getOrCreateClient();\n\t\tif (!client) {\n\t\t\treturn;\n\t\t}\n\t\tawait client.start();\n\t\tthis.updateCommands();\n\t}\n\n\tprivate async getOrCreateClient() {\n\t\tif (this.workspace.kind === \"Empty\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!this.outputChannel) {\n\t\t\tthis.outputChannel = vscode.window.createOutputChannel(\n\t\t\t\t\"V Analyzer Language Server\",\n\t\t\t);\n\t\t\tthis.pushExtCleanup(this.outputChannel);\n\t\t}\n\n\t\tif (!this._client) {\n\t\t\tthis._serverPath = await bootstrap().catch((err) => {\n\t\t\t\tif (err instanceof AnalyzerNotInstalledError) {\n\t\t\t\t\tlog.info(\"v-analyzer is not installed\");\n\n\t\t\t\t\tconst msg = \"v-analyzer is not installed. Do you want to install it?\";\n\t\t\t\t\tvoid vscode.window\n\t\t\t\t\t\t.showInformationMessage(msg, \"Yes\", \"No\")\n\t\t\t\t\t\t.then((selected) => {\n\t\t\t\t\t\t\tif (selected == \"Yes\") {\n\t\t\t\t\t\t\t\tthis.installAnalyzerWithProgress();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthrow new AnalyzerNotInstalledError();\n\t\t\t});\n\t\t\tconst newEnv = Object.assign({}, process.env);\n\t\t\tconst folder = getWorkspaceFolder();\n\t\t\tlog.debug(\"cwd: \", folder.uri.fsPath);\n\t\t\tconst run: lc.Executable = {\n\t\t\t\tcommand: this._serverPath,\n\t\t\t\toptions: { env: newEnv, cwd: folder.uri.fsPath },\n\t\t\t};\n\n\t\t\tconst config = getWorkspaceConfig();\n\t\t\tconst connMode = config.get<string>(\"connectionMode\");\n\t\t\tconst tcpPort = config.get<number>(\"tcpMode.port\");\n\n\t\t\tif (connMode === \"tcp\") {\n\t\t\t\tlog.info(`Connecting to analyzer via TCP on port ${tcpPort}`);\n\t\t\t\tlog.info(\"Make sure to start the analyzer with the --socket flag\");\n\t\t\t\tlog.info(\"Use it only for debugging purposes!\");\n\t\t\t}\n\n\t\t\tconst serverOptions =\n\t\t\t\tconnMode === \"tcp\"\n\t\t\t\t\t? () => connectAnalyzerViaTcp(tcpPort)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\trun,\n\t\t\t\t\t\t\tdebug: run,\n\t\t\t\t\t\t};\n\n\t\t\tthis._client = await createClient(this.outputChannel, serverOptions);\n\n\t\t\tthis.pushClientCleanup(\n\t\t\t\tthis._client.onNotification(ra.serverStatus, (params) =>\n\t\t\t\t\tthis.setServerStatus(params),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn this._client;\n\t}\n\n\tasync restart() {\n\t\tawait this.stopAndDispose();\n\t\tawait this.start();\n\t}\n\n\tasync stopAndDispose() {\n\t\tif (!this._client) {\n\t\t\treturn;\n\t\t}\n\t\tlog.info(\"Disposing language client\");\n\t\tthis.updateCommands(\"disable\");\n\t\tawait this.disposeClient();\n\t}\n\n\tprivate async disposeClient() {\n\t\tthis.clientSubscriptions?.forEach((disposable) => disposable.dispose());\n\t\tthis.clientSubscriptions = [];\n\t\ttry {\n\t\t\tawait this._client?.dispose();\n\t\t} catch (e) {\n\t\t\t// for some reasons dispose() always throws an error\n\t\t\t// when restarting analyzer, ignore for now\n\t\t\t// log.error('client stop error', e)\n\t\t}\n\t\tthis._serverPath = undefined;\n\t\tthis._client = undefined;\n\t}\n\n\tprivate updateCommands(forceDisable?: \"disable\") {\n\t\tthis.commandDisposables.forEach((disposable) => disposable.dispose());\n\t\tthis.commandDisposables = [];\n\n\t\tconst clientRunning = (!forceDisable && this._client?.isRunning()) ?? false;\n\t\tconst isClientRunning = (_ctx: Context): _ctx is ContextInit => {\n\t\t\treturn clientRunning;\n\t\t};\n\n\t\tfor (const [name, factory] of Object.entries(this.commandFactories)) {\n\t\t\tconst fullName = `v-analyzer.${name}`;\n\t\t\tlet callback;\n\t\t\tif (isClientRunning(this)) {\n\t\t\t\t// we asserted that `client` is defined\n\t\t\t\tcallback = factory.enabled(this);\n\t\t\t} else if (factory.disabled) {\n\t\t\t\tcallback = factory.disabled(this);\n\t\t\t} else {\n\t\t\t\tcallback = () =>\n\t\t\t\t\tvscode.window.showErrorMessage(\n\t\t\t\t\t\t`command ${fullName} failed: v-analyzer server is not running`,\n\t\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.commandDisposables.push(\n\t\t\t\tvscode.commands.registerCommand(fullName, callback),\n\t\t\t);\n\t\t}\n\t}\n\n\tshowLanguageStatusBar() {\n\t\tconst statusBar = this.langStatusBar;\n\t\tstatusBar.text = \"V\";\n\t\tstatusBar.show();\n\t\trunVCommandCallback([\"-version\"], (err, stdout) => {\n\t\t\tif (err) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst version = stdout.trim().replace(\"V \", \"\");\n\t\t\tstatusBar.text = `V ${version}`;\n\t\t});\n\t}\n\n\tsetServerStatus(status: ra.ServerStatusParams | { health: \"stopped\" }) {\n\t\tif (status.health === \"error\" && status.message) {\n\t\t\tconst msg = status.message ?? \"v-analyzer server error\";\n\t\t\tconst openConfig = \"Open Config\";\n\t\t\tvscode.window.showErrorMessage(msg, openConfig).then((selected) => {\n\t\t\t\tif (selected === openConfig) {\n\t\t\t\t\tvscode.commands.executeCommand(\"v-analyzer.openGlobalConfig\");\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tlet icon = \"\";\n\t\tconst statusBar = this.statusBar;\n\t\tstatusBar.show();\n\t\tstatusBar.tooltip = new vscode.MarkdownString(\"\", true);\n\t\tstatusBar.tooltip.isTrusted = true;\n\t\tswitch (status.health) {\n\t\t\tcase \"ok\":\n\t\t\t\tstatusBar.tooltip.appendText(status.message ?? \"Ready\");\n\t\t\t\tstatusBar.color = undefined;\n\t\t\t\tstatusBar.backgroundColor = undefined;\n\t\t\t\tstatusBar.command = \"v-analyzer.stopServer\";\n\t\t\t\ticon = \"$(zap) \";\n\t\t\t\tbreak;\n\t\t\tcase \"warning\":\n\t\t\t\tif (status.message) {\n\t\t\t\t\tstatusBar.tooltip.appendText(status.message);\n\t\t\t\t}\n\t\t\t\tstatusBar.color = new vscode.ThemeColor(\n\t\t\t\t\t\"statusBarItem.warningForeground\",\n\t\t\t\t);\n\t\t\t\tstatusBar.backgroundColor = new vscode.ThemeColor(\n\t\t\t\t\t\"statusBarItem.warningBackground\",\n\t\t\t\t);\n\t\t\t\tstatusBar.command = \"v-analyzer.openLogs\";\n\t\t\t\ticon = \"$(warning) \";\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tif (status.message) {\n\t\t\t\t\tstatusBar.tooltip.appendText(status.message);\n\t\t\t\t}\n\t\t\t\tstatusBar.color = new vscode.ThemeColor(\"statusBarItem.errorForeground\");\n\t\t\t\tstatusBar.backgroundColor = new vscode.ThemeColor(\n\t\t\t\t\t\"statusBarItem.errorBackground\",\n\t\t\t\t);\n\t\t\t\tstatusBar.command = \"v-analyzer.openGlobalConfig\";\n\t\t\t\ticon = \"$(error) \";\n\t\t\t\tbreak;\n\t\t\tcase \"stopped\":\n\t\t\t\tstatusBar.tooltip.appendText(\"Server is stopped\");\n\t\t\t\tstatusBar.tooltip.appendMarkdown(\n\t\t\t\t\t\"\\n\\n[Start server](command:v-analyzer.startServer)\",\n\t\t\t\t);\n\t\t\t\tstatusBar.color = undefined;\n\t\t\t\tstatusBar.backgroundColor = undefined;\n\t\t\t\tstatusBar.command = \"v-analyzer.startServer\";\n\t\t\t\tstatusBar.text = `$(stop-circle) v-analyzer`;\n\t\t\t\treturn;\n\t\t}\n\t\tif (statusBar.tooltip.value) {\n\t\t\tstatusBar.tooltip.appendText(\"\\n\\n\");\n\t\t}\n\t\tstatusBar.tooltip.appendMarkdown(\n\t\t\t\"\\n\\n[Restart server](command:v-analyzer.restartServer)\",\n\t\t);\n\t\tstatusBar.tooltip.appendMarkdown(\n\t\t\t\"\\n\\n[Stop server](command:v-analyzer.stopServer)\",\n\t\t);\n\t\tif (!status.quiescent) icon = \"$(sync~spin) \";\n\t\tstatusBar.text = `${icon}v-analyzer`;\n\t}\n\n\tpushExtCleanup(d: Disposable) {\n\t\tthis.extCtx.subscriptions.push(d);\n\t}\n\n\tprivate pushClientCleanup(d: Disposable) {\n\t\tthis.clientSubscriptions.push(d);\n\t}\n\n\tprivate getScriptPath(): string {\n\t\tconst globalFolder = this.extCtx.globalStorageUri.fsPath;\n\t\tif (!fs.existsSync(globalFolder)) {\n\t\t\tfs.mkdirSync(globalFolder);\n\t\t}\n\n\t\treturn path.join(globalFolder, \"install.vsh\");\n\t}\n\n\tprivate installAnalyzerWithProgress() {\n\t\treturn vscode.window.withProgress(\n\t\t\t{\n\t\t\t\ttitle: \"Installing v-analyzer...\",\n\t\t\t\tlocation: vscode.ProgressLocation.Notification,\n\t\t\t},\n\t\t\tasync (progress) => {\n\t\t\t\treturn this.installAnalyzer(progress);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate cleanOutput(value: string): string {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn value.replace(/\\u001b\\[[0-9;]*m/g, \"\");\n\t}\n\n\tprivate async startInstallation(\n\t\tprogress: Progress<{\n\t\t\tmessage?: string;\n\t\t\tincrement?: number;\n\t\t}>,\n\t\tfromSources: boolean,\n\t) {\n\t\tconst progressMessage = fromSources\n\t\t\t? \"Installing v-analyzer from sources...\"\n\t\t\t: \"Installing v-analyzer binary...\";\n\t\tprogress.report({ message: progressMessage });\n\n\t\tconst scriptPath = this.getScriptPath();\n\t\tconst buf = cp.spawnSync(`v`, [\"run\", scriptPath, \"--no-interaction\"], {\n\t\t\tencoding: \"utf-8\",\n\t\t});\n\n\t\tlog.debug(this.cleanOutput(buf.stdout));\n\t\tlog.debug(this.cleanOutput(buf.stderr));\n\n\t\tif (buf.error) {\n\t\t\tlog.error(buf.error);\n\t\t\treturn;\n\t\t}\n\n\t\tvoid vscode.window.showInformationMessage(\n\t\t\t\"v-analyzer binary has been installed successfully\",\n\t\t);\n\n\t\tprogress.report({ message: \"v-analyzer binary has been installed successfully\" });\n\n\t\tconst config = vscode.workspace.getConfiguration();\n\t\tconfig\n\t\t\t.update(\n\t\t\t\t\"v-analyzer.serverPath\",\n\t\t\t\t\"~/.config/v-analyzer/bin/v-analyzer\",\n\t\t\t\tvscode.ConfigurationTarget.Global,\n\t\t\t)\n\t\t\t.then(() => {\n\t\t\t\tlog.info(\n\t\t\t\t\t\"v-analyzer.serverPath has been updated to ~/.config/v-analyzer/bin/v-analyzer\",\n\t\t\t\t);\n\t\t\t});\n\t}\n\n\tprivate async installAnalyzer(\n\t\tprogress: Progress<{\n\t\t\tmessage?: string;\n\t\t\tincrement?: number;\n\t\t}>,\n\t) {\n\t\tawait this.downloadScriptIfNeeded();\n\n\t\tprogress.report({ message: \"Check prebuilt binary availability...\" });\n\n\t\tconst scriptPath = this.getScriptPath();\n\n\t\tconst result = cp.execSync(`v run '${scriptPath}' check-availability`, {\n\t\t\tencoding: \"utf-8\",\n\t\t});\n\t\tif (result.trim().includes(\"v-analyzer binary is available for your platform\")) {\n\t\t\tprogress.report({\n\t\t\t\tmessage:\n\t\t\t\t\t\"Found prebuilt binary for your platform, starting downloading...\",\n\t\t\t});\n\t\t\treturn this.startInstallation(progress, false);\n\t\t}\n\n\t\treturn vscode.window\n\t\t\t.showInformationMessage(\n\t\t\t\t\"v-analyzer binary is not available for your platform. Do you want to build it from source?\",\n\t\t\t\t\"Yes\",\n\t\t\t\t\"No\",\n\t\t\t)\n\t\t\t.then(async (selected) => {\n\t\t\t\tif (selected == \"Yes\") {\n\t\t\t\t\tawait this.startInstallation(progress, true);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate async downloadScriptIfNeeded() {\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst destinationPath = this.getScriptPath();\n\t\t\tif (fs.existsSync(destinationPath)) {\n\t\t\t\t// Do nothing if a script already exists\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlog.info(\"Downloading install script...\");\n\n\t\t\tconst file = fs.createWriteStream(destinationPath);\n\n\t\t\thttps\n\t\t\t\t.get(\n\t\t\t\t\t\"https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh\",\n\t\t\t\t\t(response) => {\n\t\t\t\t\t\tresponse.pipe(file);\n\t\t\t\t\t\tfile.on(\"finish\", () => {\n\t\t\t\t\t\t\tfile.close();\n\t\t\t\t\t\t\tlog.info(\"Install script has been downloaded successfully\");\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\t.on(\"error\", (err) => {\n\t\t\t\t\tfs.unlink(destinationPath, () => {\n\t\t\t\t\t\tlog.error(`Failed to download install script: ${err}`);\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t});\n\t}\n}\n\nexport interface Disposable {\n\tdispose(): void;\n}\n"
  },
  {
    "path": "editors/code/src/exec.ts",
    "content": "import { Terminal, window } from \"vscode\";\nimport { getVExecCommand } from \"./utils\";\nimport cp, { exec, ExecException } from \"child_process\";\n\ntype ExecCallback = (error: ExecException | null, stdout: string, stderr: string) => void;\n\nlet runTerminal: Terminal = null!;\n\nfunction outputTerminal(): Terminal {\n\tif (!runTerminal) {\n\t\trunTerminal = window.createTerminal(\"V\");\n\t}\n\treturn runTerminal;\n}\n\nfunction buildCommand(args: string[]): string {\n\tconst vexe = getVExecCommand();\n\treturn `${vexe} ${args.join(\" \")}`;\n}\n\n/**\n * Run V command in V terminal inside VS Code.\n */\nexport function runVCommand(args: string[]): void {\n\tconst cmd = buildCommand(args);\n\tconst term = outputTerminal();\n\tterm.show();\n\tterm.sendText(cmd);\n}\n\n/**\n * Run V command in background.\n */\nexport function runVCommandInBackground(args: string[]): void {\n\tconst cmd = buildCommand(args);\n\tcp.exec(cmd);\n}\n\n/**\n * Run V command in background and call callback when done.\n */\nexport function runVCommandCallback(args: string[], callback: ExecCallback): void {\n\tconst cmd = buildCommand(args);\n\texec(cmd, callback);\n}\n"
  },
  {
    "path": "editors/code/src/extension.ts",
    "content": "import * as vscode from \"vscode\";\nimport * as commands from \"./commands\";\nimport {\n\tAnalyzerNotInstalledError,\n\tCommandFactory,\n\tContext,\n\tfetchWorkspace,\n} from \"./ctx\";\nimport { WelcomePanel } from \"./welcome\";\nimport { setContextValue } from \"./utils\";\nimport { setGlobalState } from \"./stateUtils\";\n\nconst V_PROJECT_CONTEXT_NAME = \"inVlangProject\";\n\n/**\n * This method is called when the extension is activated.\n * @param context The extension context\n */\nexport async function activate(context: vscode.ExtensionContext): Promise<Context> {\n\tif (vscode.extensions.getExtension(\"vlanguage.vscode-vlang\")) {\n\t\tvscode.window\n\t\t\t.showWarningMessage(\n\t\t\t\t\"You have both the v-analyzer and V plugins enabled.\" +\n\t\t\t\t\t\"These are known to conflict and cause various functions of \" +\n\t\t\t\t\t\"both plugins to not work correctly. \" +\n\t\t\t\t\t\"v-analyzer provides all the features of the V plugin and more. \" +\n\t\t\t\t\t\"Disable the V plugin to avoid conflicts.\",\n\t\t\t\t\"Got it\",\n\t\t\t)\n\t\t\t.then(() => {}, console.error);\n\t}\n\n\tconst ctx = new Context(context, createCommands(), fetchWorkspace());\n\tsetGlobalState(context.globalState);\n\n\tWelcomePanel.activate(ctx);\n\n\tconst api = await activateServer(ctx).catch((err) => {\n\t\tif (!(err instanceof AnalyzerNotInstalledError)) {\n\t\t\tvoid vscode.window.showErrorMessage(\n\t\t\t\t`Cannot activate v-analyzer extension: ${err.message}`,\n\t\t\t);\n\t\t\tthrow err;\n\t\t}\n\n\t\t// If v-analyzer is not installed, we still want to activate the extension.\n\t\treturn ctx;\n\t});\n\n\t// Set the context variable inVlangProject which can be referenced when configuring,\n\t// for example, shortcuts or other things in package.json.\n\t// See https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts\n\tsetContextValue(V_PROJECT_CONTEXT_NAME, true);\n\n\treturn api;\n}\n\nexport function deactivate(): void {\n\tsetContextValue(V_PROJECT_CONTEXT_NAME, undefined);\n}\n\nasync function activateServer(ctx: Context): Promise<Context> {\n\tvscode.workspace.onDidChangeConfiguration(\n\t\t(e: vscode.ConfigurationChangeEvent) => {\n\t\t\tif (!e.affectsConfiguration(\"v-analyzer\")) return;\n\n\t\t\tvoid vscode.window\n\t\t\t\t.showInformationMessage(\n\t\t\t\t\t\"v-analyzer: Restart is required for changes to take effect. Would you like to proceed?\",\n\t\t\t\t\t\"Yes\",\n\t\t\t\t\t\"No\",\n\t\t\t\t)\n\t\t\t\t.then((selected) => {\n\t\t\t\t\tif (selected == \"Yes\") {\n\t\t\t\t\t\tvoid vscode.commands.executeCommand(\"v-analyzer.restartServer\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t},\n\t\tnull,\n\t\tctx.subscriptions,\n\t);\n\n\tawait ctx.start();\n\treturn ctx;\n}\n\nfunction createCommands(): Record<string, CommandFactory> {\n\treturn {\n\t\trestartServer: {\n\t\t\tenabled: (ctx) => async () => {\n\t\t\t\tawait ctx.restart();\n\t\t\t},\n\t\t\tdisabled: (ctx) => async () => {\n\t\t\t\tawait ctx.start();\n\t\t\t},\n\t\t},\n\t\tstartServer: {\n\t\t\tenabled: (ctx) => async () => {\n\t\t\t\tawait ctx.start();\n\t\t\t},\n\t\t\tdisabled: (ctx) => async () => {\n\t\t\t\tawait ctx.start();\n\t\t\t},\n\t\t},\n\t\tstopServer: {\n\t\t\tenabled: (ctx) => async () => {\n\t\t\t\tawait ctx.stopAndDispose();\n\t\t\t\tctx.setServerStatus({\n\t\t\t\t\thealth: \"stopped\",\n\t\t\t\t});\n\t\t\t},\n\t\t\tdisabled: (_) => async () => {},\n\t\t},\n\t\trunWorkspace: { enabled: commands.runWorkspace },\n\t\trunFile: { enabled: commands.runFile },\n\t\trunTests: { enabled: commands.runTests },\n\t\tversion: { enabled: commands.version },\n\t\tserverVersion: { enabled: commands.serverVersion },\n\t\tshowReferences: { enabled: commands.showReferences },\n\t\tviewStubTree: { enabled: commands.viewStubTree },\n\t\tuploadToPlayground: { enabled: commands.uploadToPlayground },\n\t\tshowWelcome: {\n\t\t\tenabled: WelcomePanel.showWelcome,\n\t\t\tdisabled: WelcomePanel.showWelcome,\n\t\t},\n\t\topenGlobalConfig: {\n\t\t\tenabled: commands.openGlobalConfig,\n\t\t\tdisabled: commands.openGlobalConfig,\n\t\t},\n\t};\n}\n"
  },
  {
    "path": "editors/code/src/log.ts",
    "content": "import vscode from \"vscode\";\nimport { inspect } from \"util\";\n\nexport const log = new (class {\n\tprivate enabled = true;\n\tprivate readonly output = vscode.window.createOutputChannel(\"V Analyzer Client\");\n\n\tsetEnabled(yes: boolean): void {\n\t\tlog.enabled = yes;\n\t}\n\n\t// Hint: the type [T, ...T[]] means a non-empty array\n\tdebug(...msg: [unknown, ...unknown[]]): void {\n\t\tif (!log.enabled) return;\n\t\tlog.write(\"DEBUG\", ...msg);\n\t}\n\n\tinfo(...msg: [unknown, ...unknown[]]): void {\n\t\tlog.write(\"INFO\", ...msg);\n\t}\n\n\twarn(...msg: [unknown, ...unknown[]]): void {\n\t\tdebugger;\n\t\tlog.write(\"WARN\", ...msg);\n\t}\n\n\terror(...msg: [unknown, ...unknown[]]): void {\n\t\tdebugger;\n\t\tlog.write(\"ERROR\", ...msg);\n\t\tlog.output.show(true);\n\t}\n\n\tprivate write(label: string, ...messageParts: unknown[]): void {\n\t\tconst message = messageParts.map(log.stringify).join(\" \");\n\t\tconst dateTime = new Date().toLocaleString();\n\t\tlog.output.appendLine(`${label} [${dateTime}]: ${message}`);\n\t}\n\n\tprivate stringify(val: unknown): string {\n\t\tif (typeof val === \"string\") return val;\n\t\treturn inspect(val, {\n\t\t\tcolors: false,\n\t\t\tdepth: 6, // heuristic\n\t\t});\n\t}\n})();\n"
  },
  {
    "path": "editors/code/src/lsp_ext.ts",
    "content": "import * as lc from \"vscode-languageclient\";\n\nexport const serverStatus = new lc.NotificationType<ServerStatusParams>(\n\t\"experimental/serverStatus\",\n);\n\nexport type ServerStatusParams = {\n\thealth: \"ok\" | \"warning\" | \"error\";\n\tquiescent: boolean;\n\tmessage?: string;\n};\n\nexport const viewStubTree = new lc.RequestType<lc.TextDocumentIdentifier, string, void>(\n\t\"v-analyzer/viewStubTree\",\n);\n"
  },
  {
    "path": "editors/code/src/stateUtils.ts",
    "content": "import vscode from \"vscode\";\n\nlet globalState: vscode.Memento;\n\nexport function getFromGlobalState(key: string, defaultValue?: any): any {\n\tif (!globalState) {\n\t\treturn defaultValue;\n\t}\n\treturn globalState.get(key, defaultValue);\n}\n\nexport function updateGlobalState(key: string, value: any) {\n\tif (!globalState) {\n\t\treturn Promise.resolve();\n\t}\n\treturn globalState.update(key, value);\n}\n\nexport function setGlobalState(state: vscode.Memento) {\n\tglobalState = state;\n}\n"
  },
  {
    "path": "editors/code/src/tcp.ts",
    "content": "import { StreamInfo } from \"vscode-languageclient/node\";\nimport * as net from \"net\";\n\nexport function connectAnalyzerViaTcp(port: number): Promise<StreamInfo> {\n\tconst socket = net.connect({ port });\n\tconst result: StreamInfo = {\n\t\twriter: socket,\n\t\treader: socket,\n\t};\n\treturn Promise.resolve(result);\n}\n"
  },
  {
    "path": "editors/code/src/utils.ts",
    "content": "import * as vscode from \"vscode\";\n\n/**\n * Get V executable command.\n * Will get from user setting configuration first.\n * If user don't specify it, then get default command\n */\nexport function getVExecCommand(): string {\n\tconst config = getWorkspaceConfig();\n\treturn config.get(\"v.executablePath\", \"v\");\n}\n\n/**\n * Get v-analyzer configuration.\n */\nexport function getWorkspaceConfig(): vscode.WorkspaceConfiguration {\n\tconst currentWorkspaceFolder = getWorkspaceFolder();\n\tconst uri = currentWorkspaceFolder ? currentWorkspaceFolder.uri : null;\n\treturn vscode.workspace.getConfiguration(\"v-analyzer\", uri);\n}\n\n/**\n * Get the workspace of a current document.\n * @param uri The URI of document\n */\nexport function getWorkspaceFolder(uri?: vscode.Uri): vscode.WorkspaceFolder {\n\tif (uri) {\n\t\treturn vscode.workspace.getWorkspaceFolder(uri)!;\n\t}\n\n\tif (\n\t\tvscode.workspace.workspaceFolders &&\n\t\tvscode.workspace.workspaceFolders.length > 0\n\t) {\n\t\treturn vscode.workspace.workspaceFolders[0];\n\t}\n\n\tif (vscode.window.activeTextEditor && vscode.window.activeTextEditor.document) {\n\t\treturn vscode.workspace.getWorkspaceFolder(\n\t\t\tvscode.window.activeTextEditor.document.uri,\n\t\t)!;\n\t}\n\n\treturn null!;\n}\n\n/**\n * Sets ['when'](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts)\n * clause contexts\n */\nexport function setContextValue(key: string, value: any): Thenable<void> {\n\treturn vscode.commands.executeCommand(\"setContext\", key, value);\n}\n\nexport type VlangDocument = vscode.TextDocument & { languageId: \"v\" };\nexport type VlangEditor = vscode.TextEditor & { document: VlangDocument };\n\nexport function isVlangDocument(\n\tdocument: vscode.TextDocument,\n): document is VlangDocument {\n\treturn document.languageId === \"v\" && document.uri.scheme === \"file\";\n}\n\nexport function isVlangEditor(editor: vscode.TextEditor): editor is VlangEditor {\n\treturn isVlangDocument(editor.document);\n}\n\nexport function sleep(ms: number) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n"
  },
  {
    "path": "editors/code/src/welcome.ts",
    "content": "import vscode from \"vscode\";\nimport path from \"path\";\nimport semver from \"semver\";\nimport { Command, ContextInit } from \"./ctx\";\nimport { getFromGlobalState, updateGlobalState } from \"./stateUtils\";\n\n// Most of this code is copied from the Go extension's welcome.ts file. <3\n\nexport class WelcomePanel {\n\tpublic static showWelcome(ctx: ContextInit): Command {\n\t\treturn WelcomePanel.createOrShow(ctx);\n\t}\n\n\tpublic static activate(ctx: ContextInit) {\n\t\tif (vscode.window.registerWebviewPanelSerializer) {\n\t\t\t// Make sure we register a serializer in activation event\n\t\t\tvscode.window.registerWebviewPanelSerializer(WelcomePanel.viewType, {\n\t\t\t\tasync deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel) {\n\t\t\t\t\tWelcomePanel.revive(webviewPanel, ctx.extCtx.extensionUri);\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tshowGoWelcomePage();\n\t}\n\n\tpublic static currentPanel: WelcomePanel | undefined;\n\n\tpublic static readonly viewType = \"welcomeV\";\n\n\tpublic static createOrShow(ctx: ContextInit) {\n\t\treturn () => {\n\t\t\tconst extensionUri = ctx.extCtx.extensionUri;\n\t\t\tconst column = vscode.window.activeTextEditor\n\t\t\t\t? vscode.window.activeTextEditor.viewColumn\n\t\t\t\t: undefined;\n\n\t\t\t// If we already have a panel, show it.\n\t\t\tif (WelcomePanel.currentPanel) {\n\t\t\t\tWelcomePanel.currentPanel.panel.reveal(column);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise, create a new panel.\n\t\t\tconst panel = vscode.window.createWebviewPanel(\n\t\t\t\tWelcomePanel.viewType,\n\t\t\t\t\"V for VS Code\",\n\t\t\t\tcolumn || vscode.ViewColumn.One,\n\t\t\t\t{\n\t\t\t\t\t// And restrict the webview to only loading content from our extension's directory.\n\t\t\t\t\tlocalResourceRoots: [joinPath(extensionUri)],\n\t\t\t\t},\n\t\t\t);\n\t\t\tpanel.iconPath = joinPath(extensionUri, \"media\", \"logo.png\");\n\n\t\t\tWelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);\n\t\t};\n\t}\n\n\tpublic static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {\n\t\tWelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);\n\t}\n\n\tpublic readonly dataroot: vscode.Uri; // exported for testing.\n\tprivate readonly panel: vscode.WebviewPanel;\n\tprivate readonly extensionUri: vscode.Uri;\n\tprivate disposables: vscode.Disposable[] = [];\n\n\tprivate constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {\n\t\tthis.panel = panel;\n\t\tthis.extensionUri = extensionUri;\n\t\tthis.dataroot = joinPath(this.extensionUri, \"media\");\n\n\t\t// Set the webview's initial html content\n\t\tthis.update();\n\n\t\t// Listen for when the panel is disposed\n\t\t// This happens when the user closes the panel or when the panel is closed programmatically\n\t\tthis.panel.onDidDispose(() => this.dispose(), null, this.disposables);\n\t}\n\n\tpublic dispose() {\n\t\tWelcomePanel.currentPanel = undefined;\n\n\t\t// Clean up our resources\n\t\tthis.panel.dispose();\n\n\t\twhile (this.disposables.length) {\n\t\t\tconst x = this.disposables.pop();\n\t\t\tif (x) {\n\t\t\t\tx.dispose();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate update() {\n\t\tconst webview = this.panel.webview;\n\t\tthis.panel.webview.html = this.getHtmlForWebview(webview);\n\t}\n\n\tprivate getHtmlForWebview(webview: vscode.Webview) {\n\t\tconst vAnalyzerExtension = vscode.extensions.getExtension(\n\t\t\t\"VOSCA.vscode-v-analyzer\",\n\t\t)!;\n\t\tconst vAnalyzerExtensionVersion = vAnalyzerExtension.packageJSON.version;\n\n\t\tconst stylePath = joinPath(this.dataroot, \"welcome.css\");\n\t\tconst logoPath = joinPath(this.dataroot, \"logo.png\");\n\t\tconst stylesURI = webview.asWebviewUri(stylePath);\n\t\tconst logoURI = webview.asWebviewUri(logoPath);\n\n\t\treturn `<!DOCTYPE html>\n\t\t\t<html lang=\"en\">\n\t\t\t<head>\n\t\t\t\t<meta charset=\"UTF-8\">\n\t\t\t\t<!--\n\t\t\t\t\tUse a content security policy to only allow loading images from https or from our extension directory,\n\t\t\t\t\tand only allow scripts that have a specific nonce.\n\t\t\t\t-->\n\t\t\t\t<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:;\">\n\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\t\t\t\t<link href=\"${stylesURI}\" rel=\"stylesheet\">\n\t\t\t\t<title>V for VS Code</title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t<main class=\"Content\">\n\t\t\t\t<div class=\"Header\">\n\t\t\t\t\t<img src=\"${logoURI}\" alt=\"v-analyzer logo\" class=\"Header-logo\"/>\n\t\t\t\t\t<div class=\"Header-details\">\n\t\t\t\t\t\t<h1 class=\"Header-title\">V for VS Code v${vAnalyzerExtensionVersion}</h1>\n\t\t\t\t\t\t<p>The v-analyzer extension for Visual Studio Code, providing rich language support for V projects.</p>\n\t\t\t\t\t\t<ul class=\"Header-links\">\n\t\t\t\t\t\t\t<li><a href=\"https://github.com/vlang/v-analyzer/blob/main/editors/code/CHANGELOG.md\">Release notes</a></li>\n\t\t\t\t\t\t\t<li><a href=\"https://github.com/vlang/v-analyzer\">GitHub</a></li>\n\t\t\t\t\t\t\t<li><a href=\"https://discord.gg/vlang\">Discord</a></li>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"Cards\">\n\t\t\t\t\t<div class=\"Card\">\n\t\t\t\t\t\t<div class=\"Card-inner\">\n\t\t\t\t\t\t\t<p class=\"Card-title\">Getting started</p>\n\t\t\t\t\t\t\t<p class=\"Card-content\">Learn about the v-analyzer extension in\n\t\t\t\t\t\t\t\t<a href=\"https://github.com/vlang/v-analyzer/tree/main/editors/code/README.md\">README</a>.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"Card\">\n\t\t\t\t\t\t<div class=\"Card-inner\">\n\t\t\t\t\t\t\t<p class=\"Card-title\">Learning V</p>\n\t\t\t\t\t\t\t<p class=\"Card-content\">If you're new to the V programming language,\n\t\t\t\t\t\t\t\t<a href=\"https://github.com/vlang/v/blob/master/doc/docs.md</a> is a great place to get started.</a>\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"Card\">\n\t\t\t\t\t\t<div class=\"Card-inner\">\n\t\t\t\t\t\t\t<p class=\"Card-title\">Troubleshooting</p>\n\t\t\t\t\t\t\t<p class=\"Card-content\">Experiencing problems? Start with\n\t\t\t\t\t\t\t\t<a href=\"https://github.com/vlang/v-analyzer/blob/main/editors/code/docs/troubleshooting.md\">troubleshooting guide</a>.\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t\t</body>\n\t\t\t</html>`;\n\t}\n}\n\nfunction joinPath(uri: vscode.Uri, ...pathFragment: string[]): vscode.Uri {\n\t// Reimplementation of\n\t// https://github.com/microsoft/vscode/blob/b251bd952b84a3bdf68dad0141c37137dac55d64/src/vs/base/common/uri.ts#L346-L357\n\t// with Node.JS path. This is a temporary workaround for https://github.com/eclipse-theia/theia/issues/8752.\n\tif (!uri.path) {\n\t\tthrow new Error(\"[UriError]: cannot call joinPaths on URI without path\");\n\t}\n\treturn uri.with({\n\t\tpath: vscode.Uri.file(path.join(uri.fsPath, ...pathFragment)).path,\n\t});\n}\n\nfunction showGoWelcomePage() {\n\t// Update this list of versions when there is a new version where we want to\n\t// show the welcome page on update.\n\tconst showVersions: string[] = [\"0.0.2\"];\n\tlet vExtensionVersion = \"0.0.2\";\n\tlet vExtensionVersionKey = \"v-analyzer.extensionVersion111\";\n\n\tconst savedVExtensionVersion = getFromGlobalState(vExtensionVersionKey, \"0.0.0\");\n\n\tif (\n\t\tshouldShowGoWelcomePage(showVersions, vExtensionVersion, savedVExtensionVersion)\n\t) {\n\t\tvscode.commands.executeCommand(\"v-analyzer.showWelcome\");\n\t}\n\tif (vExtensionVersion !== savedVExtensionVersion) {\n\t\tupdateGlobalState(vExtensionVersionKey, vExtensionVersion);\n\t}\n}\n\nexport function shouldShowGoWelcomePage(\n\tshowVersions: string[],\n\tnewVersion: string,\n\toldVersion: string,\n): boolean {\n\tif (newVersion === oldVersion) {\n\t\treturn false;\n\t}\n\tconst coercedNew = semver.coerce(newVersion);\n\tconst coercedOld = semver.coerce(oldVersion);\n\tif (!coercedNew || !coercedOld) {\n\t\treturn true;\n\t}\n\t// Both semver.coerce(0.22.0) and semver.coerce(0.22.0-rc.1) will be 0.22.0.\n\treturn (\n\t\tsemver.gte(coercedNew, coercedOld) && showVersions.includes(coercedNew.toString())\n\t);\n}\n"
  },
  {
    "path": "editors/code/syntaxes/stree.tmGrammar.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json\",\n    \"scopeName\": \"source.stree\",\n    \"patterns\": [\n        {\n            \"include\": \"#node_type\"\n        },\n        {\n            \"include\": \"#node_range_index\"\n        },\n        {\n            \"include\": \"#token_text\"\n        }\n    ],\n    \"repository\": {\n        \"node_type\": {\n            \"match\": \"^\\\\s*([a-z_][a-z_0-9]*?) (at)\",\n            \"captures\": {\n                \"1\": {\n                    \"name\": \"entity.name.function\"\n                },\n                \"2\": {\n                    \"name\": \"keyword\"\n                }\n            }\n        },\n        \"node_range_index\": {\n            \"match\": \"\\\\d+\",\n            \"name\": \"constant.numeric\"\n        },\n        \"token_text\": {\n            \"match\": \"\\\".+\\\"\",\n            \"name\": \"string\"\n        }\n    },\n    \"fileTypes\": [\n        \"stree\"\n    ]\n}"
  },
  {
    "path": "editors/code/syntaxes/tests/accessor.vv",
    "content": "// SYNTAX TEST \"source.v\" \"method accessor\"\nhello.world\n//   ^ punctuation.accessor.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/comma.vv",
    "content": "// SYNTAX TEST \"source.v\" \"comma\"\n [1, 2, 3, 4]\n// ^ punctuation.separator.comma.v\n//    ^ punctuation.separator.comma.v\n//       ^ punctuation.separator.comma.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/comment.vv",
    "content": "// SYNTAX TEST \"source.v\" \"comment\"\n   #!/usr/bin/env -S v\n// ^^ punctuation.definition.comment.shebang.v\n//   ^^^^^^^^^^^^^^^^^ meta.shebang.v\n// ^^^^^^^^^^^^^^^^^^^ comment.line.number-sign.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/comparison.vv",
    "content": "// SYNTAX TEST \"source.v\" \"comparison\"\n0 == 0\n//^^ keyword.operator.relation.v\n//   ^ constant.numeric.integer.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/dot.int.vv",
    "content": "// SYNTAX TEST \"source.v\"\nhello.int()\n//    ^^^ entity.name.function.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/escape.vv",
    "content": "// SYNTAX TEST \"source.v\"\n@type\n// ^^^^^ source.v - keyword.type.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/hashtag.vv",
    "content": "// SYNTAX TEST \"source.v\" \"hashtag\"\n#include <test>\n// ^^^^^^^^^^^^^^^ markup.bold.v\n#define foo bar\n// ^^^^^^^^^^^^ markup.bold.v\n#some javascript line\n// ^^^^^^^^^^^^^^^^^^ markup.bold.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/method.vv",
    "content": "// SYNTAX TEST \"source.v\" \"method accessor\"\nhello.method()\n//    ^^^^^^ entity.name.function.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/numbers.vv",
    "content": "// SYNTAX TEST \"source.v\" \"numbers\"\n_ := 1_000_000\n//   ^^^^^^^^^ constant.numeric.integer.v\n_ := 3_122.55\n//   ^^^^^^^^ constant.numeric.float.v\n_ := 3.14e11\n//   ^^^^^^^ constant.numeric.exponential.v\n_ := 0xF_F\n//   ^^^^^ constant.numeric.hex.v\n_ := 0o17_3\n//   ^^^^^^ constant.numeric.octal.v\n_ := 0b0_11\n//   ^^^^^^ constant.numeric.binary.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/optional.vv",
    "content": "// SYNTAX TEST \"source.v\" \"optional\"\nfn f(url string) ?string {\n//               ^ keyword.operator.optional.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/pubfn.vv",
    "content": "// SYNTAX TEST \"source.v\"\n   pubfn\n// ^^^ - storage.modifier.v\n//    ^^ - keyword.fn.v\n\n   pub fn\n// ^^^ storage.modifier.v\n//     ^^ keyword.fn.v\n\npub fn\n   // test\n// ^^ comment.line.double-slash.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/string.vv",
    "content": "// SYNTAX TEST \"source.v\" \"string\"\n_ := 'test'\n//    ^^^^ string.quoted.v\na := 1\n_ := '${a}'\n//    ^^ variable.other.interpolated.v\n_ := '\\\\'\n//    ^^ constant.character.escape.v\n_ := c'test'\n//   ^ storage.type.string.v\n_ := `r`\n//   ^^^ string.quoted.rune.v\n_ := r'\\'\n//   ^ storage.type.string.v\n//    ^^^ string.quoted.raw.v\n_ := r'\\'\n//   ^ storage.type.string.v\n//    ^^^ string.quoted.raw.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/type.vv",
    "content": "// SYNTAX TEST \"source.v\"\n   struct Foo {}\n//        ^^^ entity.name.type.v\n   union Foo {}\n//       ^^^ entity.name.type.v\n   pub interface Foo {}\n// ^^^ storage.modifier.pub.v\n//     ^^^^^^^^^ storage.type.interface.v\n//               ^^^ entity.name.type.v\n   type Foo = int\n//      ^^^ entity.name.type.v\n"
  },
  {
    "path": "editors/code/syntaxes/tests/variable.vv",
    "content": "// SYNTAX TEST \"source.v\"\n    abc := ''\n//  ^^^ variable.other.assignment.v\nmut abc := ''\n//  ^^^ variable.other.assignment.v\n    abc = ''\n//  ^^^ variable.other.assignment.v\n   abc, foo := '', ''\n// ^^^ variable.other.assignment.v\n//    ^^ - variable.other.assignment.v\n//      ^^^ variable.other.assignment.v\n   variable2 := 2\n// ^^^^^^^^^ variable.other.assignment.v\n//         ^ - constant.numeric.integer.v\n"
  },
  {
    "path": "editors/code/syntaxes/v.mod.tmLanguage.json",
    "content": "{\n\t\"scopeName\": \"source.v.mod\",\n\t\"patterns\": [\n\t\t{\n\t\t\t\"include\": \"#module-decl\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#brackets\"\n\t\t}\n\t],\n\t\"repository\": {\n\t\t\"module-decl\": {\n\t\t\t\"name\": \"keyword.module.v.mod\",\n\t\t\t\"match\": \"\\\\bModule\\\\b\"\n\t\t},\n\t\t\"brackets\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"{\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.begin.v.mod\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#field\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"end\": \"}\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.end.v.mod\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"field\": {\n\t\t\t\"name\": \"meta.definition.field.v.mod\",\n\t\t\t\"match\": \"\\\\b(\\\\w+):\"\n\t\t},\n\t\t\"string\": {\n\t\t\t\"name\": \"string.v.mod\",\n\t\t\t\"begin\": \"'|\\\"\",\n\t\t\t\"beginCaptures\": {\n\t\t\t\t\"0\": {\n\t\t\t\t\t\"name\": \"string.v.mod\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"end\": \"'|\\\"\",\n\t\t\t\"endCaptures\": {\n\t\t\t\t\"0\": {\n\t\t\t\t\t\"name\": \"string.v.mod\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "editors/code/syntaxes/v.tmLanguage.json",
    "content": "{\n\t\"name\": \"V\",\n\t\"scopeName\": \"source.v\",\n\t\"fileTypes\": [\n\t\t\".v\",\n\t\t\".vsh\",\n\t\t\".vv\"\n\t],\n\t\"patterns\": [\n\t\t{\n\t\t\t\"include\": \"#comments\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#as-is\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#attributes\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#assignment\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#module-decl\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#import-decl\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#hash-decl\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#brackets\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#builtin-fix\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#escaped-fix\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#operators\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#function-exist\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#generic\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#constants\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#type\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#enum\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#interface\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#struct\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#keywords\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#storage\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#numbers\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#strings\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#types\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#punctuations\"\n\t\t},\n\t\t{\n\t\t\t\"include\": \"#variable-assign\"\n\t\t}\n\t],\n\t\"repository\": {\n\t\t\"as-is\": {\n\t\t\t\"begin\": \"\\\\s+(as|is)\\\\s+\",\n\t\t\t\"beginCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"keyword.$1.v\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"end\": \"([\\\\w.]*)\",\n\t\t\t\"endCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"entity.name.alias.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"assignment\": {\n\t\t\t\"name\": \"meta.definition.variable.v\",\n\t\t\t\"match\": \"\\\\s+((?:\\\\:|\\\\+|\\\\-|\\\\*|/|\\\\%|\\\\&|\\\\||\\\\^)?=)\\\\s+\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#operators\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"attributes\": {\n\t\t\t\"name\": \"meta.definition.attribute.v\",\n\t\t\t\"match\": \"^\\\\s*((\\\\[)(deprecated|unsafe|console|heap|manualfree|typedef|live|inline|flag|ref_only|direct_array_access|callconv)(\\\\]))\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"meta.function.attribute.v\"\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"name\": \"punctuation.definition.begin.bracket.square.v\"\n\t\t\t\t},\n\t\t\t\t\"3\": {\n\t\t\t\t\t\"name\": \"storage.modifier.attribute.v\"\n\t\t\t\t},\n\t\t\t\t\"4\": {\n\t\t\t\t\t\"name\": \"punctuation.definition.end.bracket.square.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"variable-assign\": {\n\t\t\t\"match\": \"[a-zA-Z_]\\\\w*(?:,\\\\s*[a-zA-Z_]\\\\w*)*(?=\\\\s*(?:=|:=))\",\n\t\t\t\"captures\": {\n\t\t\t\t\"0\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"match\": \"[a-zA-Z_]\\\\w*\",\n\t\t\t\t\t\t\t\"name\": \"variable.other.assignment.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#punctuation\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"module-decl\": {\n\t\t\t\"name\": \"meta.module.v\",\n\t\t\t\"begin\": \"^\\\\s*(module)\\\\s+\",\n\t\t\t\"beginCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"keyword.module.v\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"end\": \"([\\\\w.]+)\",\n\t\t\t\"endCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"entity.name.module.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"import-decl\": {\n\t\t\t\"name\": \"meta.import.v\",\n\t\t\t\"begin\": \"^\\\\s*(import)\\\\s+\",\n\t\t\t\"beginCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"keyword.import.v\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"end\": \"([\\\\w.]+)\",\n\t\t\t\"endCaptures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"entity.name.import.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"hash-decl\": {\n\t\t\t\"name\": \"markup.bold.v\",\n\t\t\t\"begin\": \"^\\\\s*(#)\",\n\t\t\t\"end\": \"$\"\n\t\t},\n\t\t\"brackets\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"{\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"}\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"$self\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"\\\\(\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.round.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\\)\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.round.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"$self\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"\\\\[\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.square.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\\]\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.square.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"$self\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"builtin-fix\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"storage.modifier.v\",\n\t\t\t\t\t\t\t\"match\": \"(const)(?=\\\\s*\\\\()\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"keyword.$1.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\b(fn|type|enum|struct|union|interface|map|assert|sizeof|typeof|__offsetof)\\\\b(?=\\\\s*\\\\()\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"keyword.control.v\",\n\t\t\t\t\t\t\t\"match\": \"(\\\\$if|\\\\$else)(?=\\\\s*\\\\()\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"keyword.control.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\b(as|in|is|or|break|continue|unsafe|match|if|else|for|go|spawn|goto|defer|return|shared|select|rlock|lock|atomic|asm)\\\\b(?=\\\\s*\\\\()\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"match\": \"(?<!.)(i?(?:8|16|nt|64|128)|u?(?:16|32|64|128)|f?(?:32|64))(?=\\\\s*\\\\()\",\n\t\t\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\t\t\"name\": \"storage.type.numeric.v\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"name\": \"meta.expr.numeric.cast.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"match\": \"(bool|byte|byteptr|charptr|voidptr|string|rune|size_t|[ui]size)(?=\\\\s*\\\\()\",\n\t\t\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\t\t\"name\": \"storage.type.$1.v\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"name\": \"meta.expr.bool.cast.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"comments\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"comment.block.documentation.v\",\n\t\t\t\t\t\"begin\": \"/\\\\*\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.comment.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\\*/\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.comment.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#comments\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"comment.line.double-slash.v\",\n\t\t\t\t\t\"begin\": \"//\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"0\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.comment.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"$\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"comment.line.number-sign.v\",\n\t\t\t\t\t\"match\": \"(?:^|\\\\s*)(?:((#!).*))\",\n\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"meta.shebang.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.comment.shebang.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"constants\": {\n\t\t\t\"name\": \"constant.language.v\",\n\t\t\t\"match\": \"\\\\b(true|false|none)\\\\b\"\n\t\t},\n\t\t\"generic\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"meta.definition.generic.v\",\n\t\t\t\t\t\"match\": \"(?<=[\\\\w\\\\s+])(\\\\<)(\\\\w+)(\\\\>)\",\n\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.angle.begin.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"include\": \"#illegal-name\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"match\": \"\\\\w+\",\n\t\t\t\t\t\t\t\t\t\"name\": \"entity.name.generic.v\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"3\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.angle.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"function-exist\": {\n\t\t\t\"name\": \"meta.support.function.v\",\n\t\t\t\"match\": \"(\\\\w+)((?<=[\\\\w\\\\s+])(\\\\[)([\\\\w, ]+)(\\\\]))?(?=\\\\s*\\\\()\",\n\t\t\t\"captures\": {\n\t\t\t\t\"0\": {\n\t\t\t\t\t\"name\": \"meta.function.call.v\"\n\t\t\t\t},\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#illegal-name\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"match\": \"\\\\w+\",\n\t\t\t\t\t\t\t\"name\": \"entity.name.function.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#generic\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"type\": {\n\t\t\t\"name\": \"meta.definition.type.v\",\n\t\t\t\"match\": \"^\\\\s*(?:(pub)?\\\\s+)?(type)\\\\s+(\\\\w*)\\\\s+(?:\\\\w+\\\\.+)?(\\\\w*)\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"name\": \"storage.type.type.v\"\n\t\t\t\t},\n\t\t\t\t\"3\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#illegal-name\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#types\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"entity.name.type.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\w+\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"4\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#illegal-name\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#types\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"entity.name.type.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\w+\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"enum\": {\n\t\t\t\"name\": \"meta.definition.enum.v\",\n\t\t\t\"match\": \"^\\\\s*(?:(pub)?\\\\s+)?(enum)\\\\s+(?:\\\\w+\\\\.)?(\\\\w*)\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"name\": \"storage.type.enum.v\"\n\t\t\t\t},\n\t\t\t\t\"3\": {\n\t\t\t\t\t\"name\": \"entity.name.enum.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"interface\": {\n\t\t\t\"name\": \"meta.definition.interface.v\",\n\t\t\t\"match\": \"^\\\\s*(?:(pub)?\\\\s+)?(interface)\\\\s+(\\\\w*)\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"name\": \"storage.type.interface.v\"\n\t\t\t\t},\n\t\t\t\t\"3\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#illegal-name\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"entity.name.type.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\w+\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"struct\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"meta.definition.struct.v\",\n\t\t\t\t\t\"begin\": \"^\\\\s*(?:(mut|pub(?:\\\\s+mut)?|__global)\\\\s+)?(struct|union)\\\\s+([\\\\w.]+)\\\\s*|({)\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.struct.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"3\": {\n\t\t\t\t\t\t\t\"name\": \"entity.name.type.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"4\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.begin.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\\s*|(})\",\n\t\t\t\t\t\"endCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"punctuation.definition.bracket.curly.end.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#struct-access-modifier\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"match\": \"\\\\b(\\\\w+)\\\\s+([\\\\w\\\\[\\\\]\\\\*&.]+)(?:\\\\s*(=)\\\\s*((?:.(?=$|//|/\\\\*))*+))?\",\n\t\t\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\t\t\"name\": \"variable.other.property.v\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"include\": \"#numbers\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"include\": \"#brackets\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"include\": \"#types\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"match\": \"\\\\w+\",\n\t\t\t\t\t\t\t\t\t\t\t\"name\": \"storage.type.other.v\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"3\": {\n\t\t\t\t\t\t\t\t\t\"name\": \"keyword.operator.assignment.v\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"4\": {\n\t\t\t\t\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"include\": \"$self\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#types\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"$self\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"meta.definition.struct.v\",\n\t\t\t\t\t\"match\": \"^\\\\s*(?:(mut|pub(?:\\\\s+mut)?|__global))\\\\s+?(struct)\\\\s+(?:\\\\s+([\\\\w.]+))?\",\n\t\t\t\t\t\"captures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.struct.v\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"3\": {\n\t\t\t\t\t\t\t\"name\": \"entity.name.struct.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"struct-access-modifier\": {\n\t\t\t\"match\": \"(?<=\\\\s|^)(mut|pub(?:\\\\s+mut)?|__global)(:|\\\\b)\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"name\": \"storage.modifier.$1.v\"\n\t\t\t\t},\n\t\t\t\t\"2\": {\n\t\t\t\t\t\"name\": \"punctuation.separator.struct.key-value.v\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"punctuation\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.delimiter.period.dot.v\",\n\t\t\t\t\t\"match\": \"\\\\.\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.delimiter.comma.v\",\n\t\t\t\t\t\"match\": \",\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.separator.key-value.colon.v\",\n\t\t\t\t\t\"match\": \":\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.definition.other.semicolon.v\",\n\t\t\t\t\t\"match\": \";\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.definition.other.questionmark.v\",\n\t\t\t\t\t\"match\": \"\\\\?\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.hash.v\",\n\t\t\t\t\t\"match\": \"#\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"keywords\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.control.v\",\n\t\t\t\t\t\"match\": \"(\\\\$if|\\\\$else|\\\\$for)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.control.v\",\n\t\t\t\t\t\"match\": \"(?<!@)\\\\b(as|is|in|or|break|continue|unsafe|match|if|else|for|go|spawn|goto|defer|return|shared|select|rlock|lock|atomic|asm|__global|nil)\\\\b\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.$1.v\",\n\t\t\t\t\t\"match\": \"(?<!@)\\\\b(fn|type|typeof|enum|struct|implements|interface|map|assert|sizeof|__offsetof)\\\\b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"storage\": {\n\t\t\t\"name\": \"storage.modifier.v\",\n\t\t\t\"match\": \"\\\\b(const|mut|pub)\\\\b\"\n\t\t},\n\t\t\"types\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"storage.type.numeric.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\.)\\\\b(i(8|16|nt|64|128)|u(8|16|32|64|128)|f(32|64))\\\\b\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"storage.type.$1.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\.)\\\\b(bool|byte|byteptr|charptr|voidptr|string|ustring|rune)\\\\b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"operators\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.arithmetic.v\",\n\t\t\t\t\t\"match\": \"(\\\\+|\\\\-|\\\\*|\\\\/|\\\\%|\\\\+\\\\+|\\\\-\\\\-|\\\\>\\\\>|\\\\<\\\\<)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.relation.v\",\n\t\t\t\t\t\"match\": \"(\\\\=\\\\=|\\\\!\\\\=|\\\\>|\\\\<|\\\\>\\\\=|\\\\<\\\\=)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.assignment.v\",\n\t\t\t\t\t\"match\": \"(\\\\:\\\\=|\\\\=|\\\\+\\\\=|\\\\-\\\\=|\\\\*\\\\=|\\\\/\\\\=|\\\\%\\\\=|\\\\&\\\\=|\\\\|\\\\=|\\\\^\\\\=|\\\\~\\\\=|\\\\&\\\\&\\\\=|\\\\|\\\\|\\\\=|\\\\>\\\\>\\\\=|\\\\<\\\\<\\\\=)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.bitwise.v\",\n\t\t\t\t\t\"match\": \"(\\\\&|\\\\||\\\\^|\\\\~|<(?!<)|>(?!>))\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.logical.v\",\n\t\t\t\t\t\"match\": \"(\\\\&\\\\&|\\\\|\\\\||\\\\!)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"keyword.operator.optional.v\",\n\t\t\t\t\t\"match\": \"\\\\?\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"numbers\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.exponential.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)([0-9]+(_?))+(\\\\.)([0-9]+[eE][-+]?[0-9]+)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.float.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)([0-9]+(_?))+(\\\\.)([0-9]+)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.binary.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)(?:0b)(?:(?:[0-1]+)(?:_?))+\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.octal.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)(?:0o)(?:(?:[0-7]+)(?:_?))+\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.hex.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)(?:0x)(?:(?:[0-9a-fA-F]+)(?:_?))+\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.numeric.integer.v\",\n\t\t\t\t\t\"match\": \"(?<!\\\\w)(?:(?:[0-9]+)(?:[_]?))+\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"punctuations\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.accessor.v\",\n\t\t\t\t\t\"match\": \"(?:\\\\.)\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"punctuation.separator.comma.v\",\n\t\t\t\t\t\"match\": \"(?:,)\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"strings\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"`\",\n\t\t\t\t\t\"end\": \"`\",\n\t\t\t\t\t\"name\": \"string.quoted.rune.v\",\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-escaped-char\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-interpolation\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-placeholder\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"(r)'\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.string.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"'\",\n\t\t\t\t\t\"name\": \"string.quoted.raw.v\",\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-interpolation\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-placeholder\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"(r)\\\"\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.string.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\"\",\n\t\t\t\t\t\"name\": \"string.quoted.raw.v\",\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-interpolation\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-placeholder\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"(c?)'\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.string.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"'\",\n\t\t\t\t\t\"name\": \"string.quoted.v\",\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-escaped-char\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-interpolation\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-placeholder\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"begin\": \"(c?)\\\"\",\n\t\t\t\t\t\"beginCaptures\": {\n\t\t\t\t\t\t\"1\": {\n\t\t\t\t\t\t\t\"name\": \"storage.type.string.v\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": \"\\\"\",\n\t\t\t\t\t\"name\": \"string.quoted.v\",\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-escaped-char\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-interpolation\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"include\": \"#string-placeholder\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"string-escaped-char\": {\n\t\t\t\"patterns\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"constant.character.escape.v\",\n\t\t\t\t\t\"match\": \"\\\\\\\\([0-7]{3}|[\\\\$abfnrtv\\\\\\\\'\\\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"invalid.illegal.unknown-escape.v\",\n\t\t\t\t\t\"match\": \"\\\\\\\\[^0-7\\\\$xuUabfnrtv\\\\'\\\"]\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"string-interpolation\": {\n\t\t\t\"name\": \"meta.string.interpolation.v\",\n\t\t\t\"match\": \"(\\\\$(\\\\{.*?\\\\}))\",\n\t\t\t\"captures\": {\n\t\t\t\t\"1\": {\n\t\t\t\t\t\"patterns\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"variable.other.interpolated.v\",\n\t\t\t\t\t\t\t\"match\": \"\\\\$(\\\\{.*?\\\\})\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"string-placeholder\": {\n\t\t\t\"match\": \"%(\\\\[\\\\d+\\\\])?([\\\\+#\\\\-0\\\\x20]{,2}((\\\\d+|\\\\*)?(\\\\.?(\\\\d+|\\\\*|(\\\\[\\\\d+\\\\])\\\\*?)?(\\\\[\\\\d+\\\\])?)?))?[vT%tbcdoqxXUbeEfFgGsp]\",\n\t\t\t\"name\": \"constant.other.placeholder.v\"\n\t\t},\n\t\t\"illegal-name\": {\n\t\t\t\"match\": \"\\\\d\\\\w+\",\n\t\t\t\"name\": \"invalid.illegal.v\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "editors/code/tsconfig.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"module\": \"CommonJS\",\n\t\t\"moduleResolution\": \"node\",\n\t\t\"target\": \"ES6\",\n\t\t\"lib\": [\n\t\t\t\"ES2022\",\n\t\t\t\"DOM\"\n\t\t],\n\t\t\"baseUrl\": \"src\",\n\t\t\"outDir\": \"dist\",\n\t\t\"rootDir\": \"src\",\n\t\t\"allowJs\": true,\n\t\t\"diagnostics\": false,\n\t\t\"esModuleInterop\": true,\n\t\t\"incremental\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"noImplicitAny\": true,\n\t\t\"noImplicitOverride\": true,\n\t\t\"noImplicitReturns\": true,\n\t\t\"noImplicitThis\": true,\n\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"sourceMap\": false,\n\t\t\"stripInternal\": true\n\t},\n\t\"include\": [\n\t\t\"src/**/*.ts\"\n\t],\n\t\"exclude\": [\n\t\t\"node_modules\",\n\t\t\"scripts\"\n\t]\n}"
  },
  {
    "path": "install.vsh",
    "content": "#!/usr/bin/env -S v\n\n// This script is used to install and update v-analyzer.\nimport os\nimport json\nimport term\nimport time\nimport compress.szip\nimport cli\nimport net.http\n\nconst installer_version = '0.0.6'\nconst analyzer_config_dir_path = join_path(home_dir(), '.config', 'v-analyzer')\nconst analyzer_sources_dir_path = join_path(analyzer_config_dir_path, 'sources')\nconst analyzer_bin_dir_path = join_path(analyzer_config_dir_path, 'bin')\nconst analyzer_bin_file_path = join_path(analyzer_bin_dir_path, 'v-analyzer')\n\nconst is_github_job = os.getenv('GITHUB_JOB') != ''\n\nstruct ReleaseAsset {\n\ttag_name             string @[json: '-']\n\tbrowser_download_url string\n}\n\nfn (a ReleaseAsset) name() string {\n\treturn a.browser_download_url\n\t\t.all_after_last('/')\n\t\t.trim_string_right('.zip')\n}\n\nfn (a ReleaseAsset) os_arch() string {\n\tname := a.name()\n\tparts := name.split('-')\n\treturn parts[2..].join('-')\n}\n\nstruct ReleaseInfo {\n\ttag_name string\n\tassets   []ReleaseAsset\n}\n\nfn current_version() !string {\n\tversion_res := os.execute('v-analyzer --version')\n\tif version_res.exit_code != 0 {\n\t\treturn error('Failed to get current version: ${version_res.output}')\n\t}\n\n\treturn version_res.output.trim_string_left('v-analyzer version ').trim_space()\n}\n\nfn check_updates(release_type string) ! {\n\tasset := find_latest_asset(release_type) or {\n\t\tif err.msg().starts_with('Unsupported') {\n\t\t\tupdate_from_sources(true, false)!\n\t\t\treturn\n\t\t}\n\t\terrorln('Failed to find latest release: ${err}')\n\t\treturn\n\t}\n\n\tcur_version := current_version() or {\n\t\terrorln('${err}')\n\t\treturn\n\t}\n\n\tlocal_version := stable_version(cur_version)\n\tasset_version := stable_version(asset.tag_name)\n\tif local_version == asset_version {\n\t\tprintln('You already have the latest version of ${term.bold('v-analyzer')}: ${cur_version}')\n\t\treturn\n\t}\n\tprintln('New version of ${term.bold('v-analyzer')} is available: ${term.bold(asset.tag_name)}')\n}\n\nfn stable_version(ver string) string {\n\treturn ver.split('.')#[..4].join('.')\n}\n\nfn update(nightly bool, release_type string) ! {\n\tif nightly {\n\t\tprintln('Installing latest nightly version...')\n\t\tupdate_from_sources(true, true)!\n\t\treturn\n\t}\n\n\tprintln('Checking for updates...')\n\n\tprintln('Fetching latest release info from GitHub...')\n\tasset := find_latest_asset(release_type) or {\n\t\tif err.msg().starts_with('Unsupported') {\n\t\t\tupdate_from_sources(true, false)!\n\t\t\treturn\n\t\t}\n\t\terrorln('Failed to find latest release: ${err}')\n\t\treturn\n\t}\n\n\tcur_version := current_version() or {\n\t\terrorln('${err}')\n\t\treturn\n\t}\n\tasset_version := asset.tag_name\n\n\tif cur_version.trim_string_left('v') == asset_version.trim_string_left('v') {\n\t\tprintln('You already have the latest version of ${term.bold('v-analyzer')}: ${cur_version}')\n\t\treturn\n\t}\n\n\tprintln('Found new version of ${term.bold('v-analyzer')}: ${asset_version}')\n\tinstall_from_binary(asset, true)!\n}\n\nfn install(no_interaction bool, release_type string) ! {\n\tprintln('Downloading ${term.bold('v-analyzer')}...')\n\n\tprintln('Fetching latest release info from GitHub...')\n\tasset := find_latest_asset(release_type) or {\n\t\tinstall_from_sources(no_interaction)!\n\t\treturn\n\t}\n\n\tprintln('Found ${term.bold('v-analyzer')} binary for your platform: ${asset.os_arch()}')\n\tinstall_from_binary(asset, false)!\n}\n\nfn install_from_binary(asset ReleaseAsset, update bool) ! {\n\tprintln('> Download from url: ${asset.browser_download_url} ...')\n\tprint('Downloading ${term.bold('v-analyzer')} archive')\n\tos.flush()\n\n\tarchive_temp_dir := os.join_path(os.temp_dir(), 'v-analyzer', 'archive')\n\tos.mkdir_all(archive_temp_dir) or {\n\t\tprintln('Failed to create temp directory for archive: ${archive_temp_dir}')\n\t\treturn\n\t}\n\n\tarchive_temp_path := os.join_path(archive_temp_dir, 'v-analyzer.zip')\n\n\tdownload_file_with_progress(asset.browser_download_url, archive_temp_path)\n\n\tprintln('${term.green('✓')} Successfully downloaded ${term.bold('v-analyzer')} archive')\n\n\tprintln('Extracting ${term.bold('v-analyzer')} archive...')\n\tos.mkdir_all(analyzer_bin_dir_path) or {\n\t\tprintln('Failed to create directory: ${analyzer_bin_dir_path}')\n\t\treturn\n\t}\n\n\tszip.extract_zip_to_dir(archive_temp_path, analyzer_bin_dir_path) or {\n\t\tprintln('Failed to extract archive: ${err}')\n\t\treturn\n\t}\n\n\tprintln('${term.green('✓')} Successfully extracted ${term.bold('v-analyzer')} archive')\n\n\tif update {\n\t\tprintln('${term.green('✓')} ${term.bold('v-analyzer')} successfully updated to ${term.bold(asset.tag_name)}')\n\t}\n\n\tshow_info_about_binary(analyzer_bin_file_path)\n\n\tif !update {\n\t\tshow_hint_about_path_if_needed(analyzer_bin_file_path)\n\t}\n\n\tos.mkdir_all(analyzer_sources_dir_path) or {\n\t\tprintln('Failed to create directory: ${analyzer_sources_dir_path}')\n\t\treturn\n\t}\n}\n\nfn find_latest_asset(release_type string) !ReleaseAsset {\n\ttext := http.get_text('https://api.github.com/repos/vlang/v-analyzer/releases/latest')\n\tres := json.decode(ReleaseInfo, text) or {\n\t\terrorln('Failed to decode JSON response from GitHub: ${err}')\n\t\treturn error('Failed to decode JSON response from GitHub: ${err}')\n\t}\n\n\tos_ := os_name() or { return error('Unsupported OS') }\n\n\tarch := arch_name() or { return error('Unsupported architecture') }\n\n\tmut filename := build_os_arch(os_, arch)\n\tif release_type != '' {\n\t\tfilename += '-${release_type}'\n\t}\n\tasset := res.assets.filter(it.os_arch() == filename)[0] or {\n\t\treturn error('Unsupported OS or architecture')\n\t}\n\n\treturn ReleaseAsset{\n\t\t...asset\n\t\ttag_name: res.tag_name\n\t}\n}\n\n// download_file downloads file from the given URL to the given path.\n// Returns channel that will be closed when the download is finished.\n// If the download fails, the channel will be closed with false value.\nfn download_file(path string, to string) chan bool {\n\tch := chan bool{}\n\n\tspawn fn [ch, path, to] () {\n\t\thttp.download_file(path, to) or {\n\t\t\tprintln('Failed to download file: ${err}')\n\t\t\tch <- false\n\t\t\tch.close()\n\t\t\treturn\n\t\t}\n\t\tch <- true\n\t\tch.close()\n\t}()\n\n\treturn ch\n}\n\nfn download_file_with_progress(path string, to string) {\n\tch := download_file(path, to)\n\n\tfor {\n\t\tselect {\n\t\t\t_ := <-ch {\n\t\t\t\tprintln('')\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t500 * time.millisecond {\n\t\t\t\tprint('.')\n\t\t\t\tos.flush()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn build_os_arch(os_name string, arch string) string {\n\treturn '${os_name}-${arch}'\n}\n\nfn update_from_sources(update bool, nightly bool) ! {\n\tmut need_pull := true\n\tif !already_cloned() {\n\t\tclone_repository()!\n\t\tneed_pull = false\n\t}\n\n\tif need_pull {\n\t\tprintln('Updating ${term.bold('v-analyzer')} sources...')\n\n\t\tres := os.execute('git -C ${analyzer_sources_dir_path} pull')\n\t\tif res.exit_code != 0 {\n\t\t\terrorln('Failed to update sources: ${res.output}')\n\t\t\treturn\n\t\t}\n\n\t\tprintln('${term.green('✓')} Successfully updated ${term.bold('v-analyzer')} sources')\n\t}\n\n\tbuild_from_sources()!\n\n\tif update {\n\t\thash := get_latest_commit_hash() or {\n\t\t\terrorln(err.str())\n\t\t\treturn\n\t\t}\n\n\t\tupdated_version := if nightly {\n\t\t\t'nightly (${hash})'\n\t\t} else {\n\t\t\thash\n\t\t}\n\n\t\tprintln('${term.green('✓')} ${term.bold('v-analyzer')} successfully updated to ${updated_version}')\n\t}\n\n\tshow_info_about_binary(analyzer_bin_file_path)\n\treturn\n}\n\nfn show_info_about_binary(analyzer_bin_file_path string) {\n\tprintln('Path to the binary: ${term.bold(analyzer_bin_file_path)}')\n\tprintln('Size of the binary: ${term.bold(os.file_size(analyzer_bin_file_path).str())}')\n\tbversion := os.execute('${os.quoted_path(analyzer_bin_file_path)} version')\n\tprintln('Binary version: ${term.bold(bversion.output.trim_space())}')\n}\n\nfn get_latest_commit_hash() !string {\n\thash_res := os.execute('git -C ${analyzer_sources_dir_path} log -1 --format=%H')\n\tif hash_res.exit_code != 0 {\n\t\treturn error('Failed to get hash of the latest commit: ${hash_res.output}')\n\t}\n\treturn hash_res.output.trim_space()\n}\n\nconst git_clone_options = '--filter=blob:none --recursive --shallow-submodules'\n\nfn install_from_sources(no_interaction bool) ! {\n\tprintln('${term.yellow('[WARNING]')} Currently ${term.bold('v-analyzer')} has no prebuilt binaries for your platform')\n\n\t// Used primarily for VS Code extension\n\tif !(is_github_job || no_interaction) {\n\t\tmut answer := os.input('Do you want to build it from sources? (y/n) ')\n\t\tif answer != 'y' {\n\t\t\tprintln('')\n\t\t\tprintln('Ending the update process')\n\t\t\twarnln('${term.bold('v-analyzer')} is not installed!')\n\t\t\tprintln('')\n\t\t\tprintln('${term.bold('[NOTE]')} If you want to build it from sources manually, run the following commands:')\n\t\t\tprintln('git clone ${git_clone_options} https://github.com/vlang/v-analyzer.git')\n\t\t\tprintln('cd v-analyzer')\n\t\t\tprintln('v build.vsh')\n\t\t\tprintln(term.gray('# Optionally you can move the binary to the standard location:'))\n\t\t\tprintln('mkdir -p ${analyzer_bin_dir_path}')\n\t\t\tprintln('cp ./bin/v-analyzer ${analyzer_bin_dir_path}')\n\t\t\treturn\n\t\t}\n\t}\n\tprintln('... building from source ...')\n\n\tif already_cloned() {\n\t\tprintln('... removing already cloned folder ...')\n\t\tos.rmdir_all(analyzer_sources_dir_path) or {\n\t\t\terrorln('Failed to remove directory: ${analyzer_sources_dir_path}: ${err}')\n\t\t\treturn\n\t\t}\n\t}\n\n\tclone_repository()!\n\tbuild_from_sources()!\n\n\tshow_info_about_binary(analyzer_bin_file_path)\n\tshow_hint_about_path_if_needed(analyzer_bin_file_path)\n}\n\nfn clone_repository() ! {\n\tprintln('Cloning ${term.bold('v-analyzer')} repository...')\n\n\texit_code := run_command('git clone ${git_clone_options} https://github.com/vlang/v-analyzer.git ${analyzer_sources_dir_path} 2>&1') or {\n\t\terrorln('Failed to clone v-analyzer repository: ${err}')\n\t\treturn\n\t}\n\tif exit_code != 0 {\n\t\terrorln('Failed to clone v-analyzer repository')\n\t\treturn\n\t}\n\n\tprintln('${term.green('✓')} ${term.bold('v-analyzer')} repository cloned successfully')\n}\n\nfn build_from_sources() ! {\n\tprintln('Building ${term.bold('v-analyzer')}...')\n\n\tchdir(analyzer_sources_dir_path)!\n\tinstall_deps_cmd := os.execute('v install')\n\tif install_deps_cmd.exit_code != 0 {\n\t\terrorln('Failed to install dependencies for ${term.bold('v-analyzer')}')\n\t\teprintln(install_deps_cmd.output)\n\t\treturn\n\t}\n\n\tprintln('${term.green('✓')} Dependencies for ${term.bold('v-analyzer')} installed successfully')\n\n\tchdir(analyzer_sources_dir_path)!\n\texit_code := run_command('v build.vsh 1>/dev/null') or {\n\t\terrorln('Failed to build ${term.bold('v-analyzer')}: ${err}')\n\t\treturn\n\t}\n\tif exit_code != 0 {\n\t\terrorln('Failed to build ${term.bold('v-analyzer')}')\n\t\treturn\n\t}\n\n\tprintln('Moving ${term.bold('v-analyzer')} binary to the standard location...')\n\n\tos.mkdir_all(analyzer_bin_dir_path) or {\n\t\tprintln('Failed to create directory: ${analyzer_bin_dir_path}')\n\t\treturn\n\t}\n\n\tos.cp_all('${analyzer_sources_dir_path}/bin/v-analyzer' + $if windows { '.exe' } $else { '' },\n\t\tanalyzer_bin_dir_path, true) or {\n\t\tprintln('Failed to copy ${term.bold('v-analyzer')} binary to ${analyzer_bin_dir_path}: ${err}')\n\t\treturn\n\t}\n\n\tprintln('${term.green('✓')} Successfully moved ${term.bold('v-analyzer')} binary to ${analyzer_bin_dir_path}')\n\n\tprintln('${term.green('✓')} ${term.bold('v-analyzer')} built successfully')\n}\n\nfn already_cloned() bool {\n\tif !os.exists(analyzer_sources_dir_path) {\n\t\treturn false\n\t}\n\n\tfiles := os.ls(analyzer_sources_dir_path) or { return false }\n\treturn files.len > 0\n}\n\nfn show_hint_about_path_if_needed(abs_path string) {\n\tif !need_show_hint_about_path(abs_path) {\n\t\treturn\n\t}\n\n\tquoted_abs_path := '\"${abs_path}\"'\n\n\tprint('Add it to your ${term.bold('PATH')} to use it from anywhere or ')\n\tprintln('specify the full path to the binary in your editor settings')\n\tprintln('')\n\tprint('For example in VS Code ')\n\tprintln(term.bold('settings.json:'))\n\tprintln('${term.bold('{')}')\n\tprintln('    ${term.yellow('\"v-analyzer.serverPath\"')}: ${term.green(quoted_abs_path)}')\n\tprintln('${term.bold('}')}')\n}\n\nfn need_show_hint_about_path(abs_path string) bool {\n\tdir := os.dir(abs_path)\n\tpath := os.getenv('PATH')\n\tpaths := path.split(os.path_delimiter)\n\treturn paths.filter(it == dir).len == 0\n}\n\nfn os_name() ?string {\n\t$if macos {\n\t\treturn 'darwin'\n\t}\n\tname := os.user_os()\n\tif name == 'unknown' {\n\t\treturn none\n\t}\n\treturn name\n}\n\nfn arch_name() ?string {\n\t$if arm64 {\n\t\treturn 'arm64'\n\t}\n\n\t$if amd64 || x64 {\n\t\treturn 'x86_64'\n\t}\n\n\treturn none\n}\n\nfn run_command(cmd string) !int {\n\t$if windows {\n\t\tfixed_command := cmd\n\t\t\t.trim_string_right('2>&1')\n\t\t\t.trim_string_right('1>/dev/null')\n\n\t\tres := os.execute(fixed_command)\n\t\tprintln(res.output)\n\n\t\treturn res.exit_code\n\t}\n\n\tmut command := os.Command{\n\t\tpath:            cmd\n\t\tredirect_stdout: true\n\t}\n\n\tcommand.start()!\n\n\tfor !command.eof {\n\t\tprintln(command.read_line())\n\t}\n\n\tcommand.close()!\n\n\treturn command.exit_code\n}\n\npub fn errorln(msg string) {\n\teprintln('${term.red('[ERROR]')} ${msg}')\n}\n\npub fn warnln(msg string) {\n\tprintln('${term.yellow('[WARNING]')} ${msg}')\n}\n\npub fn get_release_type(cmd cli.Command) string {\n\treturn cmd.flags.get_string('debug') or {\n\t\treturn cmd.flags.get_string('dev') or {\n\t\t\tif cmd.flags.get_string('release') or { return '' } != '' {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn ''\n\t\t}\n\t}\n}\n\nfn main() {\n\tprintln('Installer version: ${term.bold(installer_version)}')\n\tmut cmd := cli.Command{\n\t\tname:        'v-analyzer-installer-updated'\n\t\tversion:     installer_version\n\t\tdescription: 'Install and update v-analyzer'\n\t\tposix_mode:  true\n\t\texecute:     fn (cmd cli.Command) ! {\n\t\t\tno_interaction := cmd.flags.get_bool('no-interaction') or { is_github_job }\n\t\t\trelease_type := get_release_type(cmd)\n\t\t\tinstall(no_interaction, release_type)!\n\t\t}\n\t\tflags:       [\n\t\t\tcli.Flag{\n\t\t\t\tflag:        .bool\n\t\t\t\tname:        'no-interaction' // Used primarily for VS Code extension, to install v-analyzer from sources\n\t\t\t\tdescription: 'Do not ask any questions, use default values'\n\t\t\t},\n\t\t]\n\t}\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'up'\n\t\tdescription: 'Update v-analyzer to the latest version'\n\t\tposix_mode:  true\n\t\texecute:     fn (cmd cli.Command) ! {\n\t\t\tnightly := cmd.flags.get_bool('nightly') or { false }\n\t\t\trelease_type := get_release_type(cmd)\n\t\t\tupdate(nightly, release_type)!\n\t\t}\n\t\tflags:       [\n\t\t\tcli.Flag{\n\t\t\t\tflag:        .bool\n\t\t\t\tname:        'nightly'\n\t\t\t\tdescription: 'Install the latest nightly build'\n\t\t\t},\n\t\t]\n\t})\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'check-availability'\n\t\tdescription: 'Check if v-analyzer binary is available for the current platform (service command for editors)'\n\t\tposix_mode:  true\n\t\texecute:     fn (cmd cli.Command) ! {\n\t\t\trelease_type := get_release_type(cmd)\n\t\t\tfind_latest_asset(release_type) or {\n\t\t\t\tprintln('Prebuild v-analyzer binary is not available for your platform')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tprintln('${term.green('✓')} Prebuild v-analyzer binary is available for your platform')\n\t\t}\n\t})\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'check-updates'\n\t\tdescription: 'Checks for v-analyzer updates.'\n\t\tposix_mode:  true\n\t\texecute:     fn (cmd cli.Command) ! {\n\t\t\trelease_type := get_release_type(cmd)\n\t\t\tcheck_updates(release_type)!\n\t\t}\n\t})\n\n\tcmd.parse(os.args)\n}\n"
  },
  {
    "path": "src/analyzer/Indexer.v",
    "content": "module analyzer\n\nimport os\nimport time\nimport loglib\nimport analyzer.index\n\n// IndexingRootsStatus describes the indexing status of all roots.\npub enum IndexingRootsStatus {\n\tall_indexed\n\tneeds_ensure_indexed // when at least one of the indexes was taken from the cache\n}\n\n// Indexer encapsulates the indexing logic and provides an interface for working with the index.\npub struct Indexer {\npub mut:\n\troots   []&index.IndexingRoot\n\tno_save bool\n}\n\npub fn new_indexer() &Indexer {\n\treturn &Indexer{}\n}\n\npub fn (mut i Indexer) set_no_save(value bool) {\n\ti.no_save = value\n\tfor mut root in i.roots {\n\t\troot.no_save = value\n\t}\n}\n\npub fn (i Indexer) count_roots() int {\n\treturn i.roots.len\n}\n\npub fn (mut i Indexer) add_indexing_root(root string, kind index.IndexingRootKind, cache_dir string) {\n\tloglib.with_fields({\n\t\t'root': root\n\t}).info('Adding indexing root')\n\ti.roots << index.new_indexing_root(root, kind, cache_dir)\n}\n\npub fn (mut i Indexer) index(on_start fn (root index.IndexingRoot, index int)) IndexingRootsStatus {\n\tnow := time.now()\n\tloglib.info('Indexing ${i.roots.len} roots')\n\n\tmut need_ensure_indexed := false\n\n\tfor index, mut indexing_root in i.roots {\n\t\ton_start(*indexing_root, index + 1)\n\t\tstatus := indexing_root.index()\n\t\tif status == .from_cache {\n\t\t\t// If at least one of the indexes was taken from the cache,\n\t\t\t// then we need to make sure that all indexes are up to date.\n\t\t\tneed_ensure_indexed = true\n\t\t}\n\t}\n\n\tloglib.with_duration(time.since(now)).info('Indexing all roots')\n\n\treturn if need_ensure_indexed {\n\t\t.needs_ensure_indexed\n\t} else {\n\t\t.all_indexed\n\t}\n}\n\npub fn (mut i Indexer) ensure_indexed() {\n\tnow := time.now()\n\tloglib.info('Ensure indexed of ${i.roots.len} roots')\n\n\tfor mut indexing_root in i.roots {\n\t\tindexing_root.ensure_indexed()\n\t}\n\n\tloglib.with_duration(time.since(now)).info('Ensure indexed of all roots')\n}\n\npub fn (mut i Indexer) save_indexes() ! {\n\tif i.no_save {\n\t\treturn\n\t}\n\n\tfor mut indexing_root in i.roots {\n\t\tindexing_root.save_index() or {\n\t\t\tloglib.with_fields({\n\t\t\t\t'root': indexing_root.root\n\t\t\t\t'err':  err.str()\n\t\t\t}).error('Failed to save index')\n\t\t\treturn err\n\t\t}\n\t}\n}\n\npub fn (mut i Indexer) mark_as_dirty(filepath string, new_content string) ! {\n\tfor mut indexing_root in i.roots {\n\t\tindexing_root.mark_as_dirty(filepath, new_content)!\n\t}\n}\n\npub fn (mut i Indexer) add_file(path string) ?index.FileIndex {\n\tcontent := os.read_file(path) or {\n\t\tloglib.with_fields({\n\t\t\t'path': path\n\t\t\t'err':  err.str()\n\t\t}).error('Failed to read new file')\n\t\treturn none\n\t}\n\n\tfor mut root in i.roots {\n\t\tif root.contains(path) {\n\t\t\treturn root.add_file(path, content) or {\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'root': root.root\n\t\t\t\t\t'path': path\n\t\t\t\t\t'err':  err.str()\n\t\t\t\t}).error('Failed to add new file')\n\t\t\t\treturn none\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (mut i Indexer) rename_file(old_path string, new_path string) ?index.FileIndex {\n\tfor mut root in i.roots {\n\t\tif root.contains(old_path) {\n\t\t\treturn root.rename_file(old_path, new_path) or {\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'root':     root.root\n\t\t\t\t\t'old_path': old_path\n\t\t\t\t\t'new_path': new_path\n\t\t\t\t\t'err':      err.str()\n\t\t\t\t}).error('Failed to rename file')\n\t\t\t\treturn none\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (mut i Indexer) remove_file(path string) ?index.FileIndex {\n\tfor mut root in i.roots {\n\t\tif root.contains(path) {\n\t\t\treturn root.remove_file(path) or {\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'root': root.root\n\t\t\t\t\t'path': path\n\t\t\t\t\t'err':  err.str()\n\t\t\t\t}).error('Failed to remove file')\n\t\t\t\treturn none\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/IndexingManager.v",
    "content": "module analyzer\n\nimport analyzer.psi\n\npub struct IndexingManager {\npub mut:\n\tindexer    &Indexer = unsafe { nil }\n\tstub_index psi.StubIndex\n}\n\npub fn IndexingManager.new() &IndexingManager {\n\tindexer := new_indexer()\n\treturn &IndexingManager{\n\t\tindexer: indexer\n\t}\n}\n\npub fn (mut a IndexingManager) setup_empty_indexes() {\n\ta.stub_index = psi.new_stubs_index([])\n\tstubs_index = a.stub_index\n}\n\npub fn (mut a IndexingManager) setup_stub_indexes() {\n\tmut sinks := a.all_sinks()\n\ta.stub_index = psi.new_stubs_index(sinks)\n\tstubs_index = a.stub_index\n}\n\npub fn (mut a IndexingManager) update_stub_indexes_from_sinks(changed_sinks []psi.StubIndexSink) {\n\tall_sinks := a.all_sinks()\n\tstubs_index.update_stubs_index(changed_sinks, all_sinks)\n}\n\npub fn (mut a IndexingManager) update_stub_indexes(changed_files []&psi.PsiFile) {\n\tall_sinks := a.all_sinks()\n\tmut changed_sinks := []psi.StubIndexSink{cap: changed_files.len}\n\n\tfor root in a.indexer.roots {\n\t\tfor file in changed_files {\n\t\t\tfile_cache := root.index.per_file.data[file.path] or { continue }\n\t\t\tchanged_sinks << file_cache.sink\n\t\t}\n\t}\n\n\tstubs_index.update_stubs_index(changed_sinks, all_sinks)\n}\n\nfn (mut a IndexingManager) all_sinks() []psi.StubIndexSink {\n\tmut sinks := []psi.StubIndexSink{cap: a.indexer.roots.len * 30}\n\tfor root in a.indexer.roots {\n\t\tsinks << root.index.per_file.get_sinks()\n\t}\n\treturn sinks\n}\n"
  },
  {
    "path": "src/analyzer/OpenedFile.v",
    "content": "module analyzer\n\nimport lsp\nimport utils\nimport analyzer.psi\n\npub struct OpenedFile {\npub mut:\n\turi      lsp.DocumentUri\n\tversion  int\n\tpsi_file &psi.PsiFile\n}\n\npub fn (f OpenedFile) find_offset(pos lsp.Position) u32 {\n\treturn u32(utils.compute_offset(f.psi_file.text(), pos.line, pos.character))\n}\n"
  },
  {
    "path": "src/analyzer/README.md",
    "content": "# Description\n\n`analyzer` module describes all the functionality related to code analysis.\n\n`server` module uses the `analyzer` module to implement all the features related to code\nanalysis.\n"
  },
  {
    "path": "src/analyzer/index/FileIndex.v",
    "content": "module index\n\nimport analyzer.psi\n\n// FileIndex describes the cache of a single file.\n// By splitting the cache into files, we can index files in parallel\n// without the need for synchronization.\n@[heap]\npub struct FileIndex {\npub mut:\n\tkind IndexingRootKind // root where the file is located\n\t// file_last_modified stores the time the file was last modified\n\t//\n\t// Thanks to it, while checking the cache, we can understand whether the\n\t// file has been changed or not.\n\t// If the file has been modified, then we reindex the file.\n\tfile_last_modified i64\n\t// stub_list is a list of all stubs in the file.\n\t// Storing stubs as a table makes it easy and compact to save them to disk and load them back.\n\tstub_list &psi.StubList = unsafe { nil }\n\t// sink describes the indexed stubs of the current file.\n\t// So, for example, by the '.functions' key, you can get the stubs of all functions defined inside the current file.\n\t// See also 'StubIndexKey'.\n\tsink &psi.StubIndexSink = unsafe { nil }\n}\n\npub fn (f &FileIndex) path() string {\n\tif f.stub_list == unsafe { nil } {\n\t\treturn ''\n\t}\n\treturn f.stub_list.path\n}\n"
  },
  {
    "path": "src/analyzer/index/Index.v",
    "content": "module index\n\nimport time\n\n// IndexNotFoundError is returned if the index is not found.\npub struct IndexNotFoundError {\n\tError\n}\n\n// NeedReindexedError is returned if the index needs to be rebuilt.\npub struct NeedReindexedError {\n\tError\n}\n\n// IndexVersionMismatchError is returned if the index version does not match the latest.\npub struct IndexVersionMismatchError {\n\tError\n}\n\n// Index encapsulates the index storage logic.\npub struct Index {\npub:\n\tversion string = '33'\npub mut:\n\tupdated_at time.Time // time of last index update\n\tper_file   PerFileIndex\n}\n\n// decode encapsulates the index decoding logic.\n// If the index was corrupted and could not be decoded, an error is returned.\n// If the index version does not match the latest, an `IndexVersionMismatchError` is returned.\npub fn (mut i Index) decode(data []u8) ! {\n\tmut d := new_index_deserializer(data)\n\tindex := d.deserialize_index(i.version)!\n\ti.per_file = index.per_file\n}\n\n// encode encapsulates the logic for encoding an index.\npub fn (i &Index) encode() []u8 {\n\tmut s := IndexSerializer{}\n\ts.serialize_index(i)\n\treturn s.s.data\n}\n"
  },
  {
    "path": "src/analyzer/index/IndexDeserializer.v",
    "content": "module index\n\nimport analyzer.psi\nimport bytes\nimport time\n\npub struct IndexDeserializer {\nmut:\n\td bytes.Deserializer\n}\n\npub fn new_index_deserializer(data []u8) IndexDeserializer {\n\treturn IndexDeserializer{\n\t\td: bytes.new_deserializer(data)\n\t}\n}\n\npub fn (mut d IndexDeserializer) deserialize_index(expected_version string) !Index {\n\tversion := d.d.read_string()\n\tif version != expected_version {\n\t\t// Due to the fact that the structure of the index can change, we cannot simply\n\t\t// restore the index if the version does not match, therefore, if there is a mismatch,\n\t\t// we stop the decoding of the index immediately.\n\t\treturn IndexVersionMismatchError{}\n\t}\n\tupdated_at_unix := d.d.read_i64()\n\tfile_indexes := d.deserialize_file_indexes()\n\n\treturn Index{\n\t\tversion:    version\n\t\tupdated_at: time.unix(updated_at_unix)\n\t\tper_file:   PerFileIndex{\n\t\t\tdata: file_indexes\n\t\t}\n\t}\n}\n\npub fn (mut d IndexDeserializer) deserialize_file_indexes() map[string]FileIndex {\n\tlen := d.d.read_int()\n\tmut file_indexes := map[string]FileIndex{}\n\tfor _ in 0 .. len {\n\t\tfile_index := d.deserialize_file_index()\n\t\tfile_indexes[file_index.path()] = file_index\n\t}\n\treturn file_indexes\n}\n\npub fn (mut d IndexDeserializer) deserialize_file_index() FileIndex {\n\tkind := unsafe { IndexingRootKind(d.d.read_u8()) }\n\tfile_last_modified := d.d.read_i64()\n\n\tstub_list := d.deserialize_stub_list()\n\tstub_index_sink := d.deserialize_stub_index_sink(stub_list, kind)\n\n\treturn FileIndex{\n\t\tkind:               kind\n\t\tfile_last_modified: file_last_modified\n\t\tstub_list:          stub_list\n\t\tsink:               stub_index_sink\n\t}\n}\n\npub fn (mut d IndexDeserializer) deserialize_stub_index_sink(stub_list &psi.StubList, kind IndexingRootKind) &psi.StubIndexSink {\n\tlen := d.d.read_int()\n\tmut sink := &psi.StubIndexSink{\n\t\tstub_list: stub_list\n\t\tkind:      unsafe { psi.StubIndexLocationKind(u8(kind)) }\n\t}\n\tfor _ in 0 .. len {\n\t\tkey := d.d.read_int()\n\t\tmut sink_map := d.deserialize_stub_index_sink_map()\n\t\tsink.data[key] = sink_map.move()\n\t}\n\tcount_imported_modules := d.d.read_int()\n\tmut imported_modules := []string{cap: count_imported_modules}\n\tfor _ in 0 .. count_imported_modules {\n\t\timported_modules << d.d.read_string()\n\t}\n\tsink.imported_modules = imported_modules\n\treturn sink\n}\n\npub fn (mut d IndexDeserializer) deserialize_stub_index_sink_map() map[string][]psi.StubId {\n\tlen := d.d.read_int()\n\tmut sink_map := map[string][]psi.StubId{}\n\tfor _ in 0 .. len {\n\t\tkey := d.d.read_string()\n\t\tstub_ids_len := d.d.read_int()\n\t\tmut stub_ids := []psi.StubId{cap: stub_ids_len}\n\t\tfor _ in 0 .. stub_ids_len {\n\t\t\tstub_ids << d.d.read_int()\n\t\t}\n\t\tsink_map[key] = stub_ids\n\t}\n\treturn sink_map\n}\n\npub fn (mut d IndexDeserializer) deserialize_stub_list() &psi.StubList {\n\tfilepath := d.d.read_string()\n\tmodule_fqn := d.d.read_string()\n\tmut child_map := map[psi.StubId][]int{}\n\tlen := d.d.read_int()\n\tfor _ in 0 .. len {\n\t\tid := d.d.read_int()\n\t\tchildren_len := d.d.read_int()\n\t\tmut children := []int{cap: children_len}\n\t\tfor _ in 0 .. children_len {\n\t\t\tchildren << d.d.read_int()\n\t\t}\n\t\tchild_map[id] = children\n\t}\n\n\tstubs_count := d.d.read_int()\n\tmut stubs := []&psi.StubBase{cap: stubs_count}\n\tfor _ in 0 .. stubs_count {\n\t\tstubs << d.deserialize_stub()\n\t}\n\n\tmut index_map := map[psi.StubId]&psi.StubBase{}\n\tfor stub in stubs {\n\t\tindex_map[stub.id] = stub\n\t}\n\n\tmut list := &psi.StubList{}\n\tlist.module_fqn = module_fqn\n\tlist.path = filepath\n\tlist.index_map = index_map.move()\n\tlist.child_map = child_map.move()\n\n\tfor _, mut stub in list.index_map {\n\t\tstub.stub_list = list\n\t}\n\n\treturn list\n}\n\npub fn (mut d IndexDeserializer) deserialize_stub() &psi.StubBase {\n\ttext := d.d.read_string()\n\tcomment := d.d.read_string()\n\treceiver := d.d.read_string()\n\tadditional := d.d.read_string()\n\tname := d.d.read_string()\n\n\tidentifier_line := d.d.read_int()\n\tidentifier_column := d.d.read_int()\n\tidentifier_end_line := d.d.read_int()\n\tidentifier_end_column := d.d.read_int()\n\n\tline := d.d.read_int()\n\tcolumn := d.d.read_int()\n\tend_line := d.d.read_int()\n\tend_column := d.d.read_int()\n\n\tparent_id := d.d.read_int()\n\tstub_type := unsafe { psi.StubType(d.d.read_u8()) }\n\tid := d.d.read_int()\n\n\treturn &psi.StubBase{\n\t\ttext:                  text\n\t\tcomment:               comment\n\t\treceiver:              receiver\n\t\tadditional:            additional\n\t\tname:                  name\n\t\tidentifier_text_range: psi.TextRange{\n\t\t\tline:       identifier_line\n\t\t\tcolumn:     identifier_column\n\t\t\tend_line:   identifier_end_line\n\t\t\tend_column: identifier_end_column\n\t\t}\n\t\ttext_range:            psi.TextRange{\n\t\t\tline:       line\n\t\t\tcolumn:     column\n\t\t\tend_line:   end_line\n\t\t\tend_column: end_column\n\t\t}\n\t\tparent_id:             parent_id\n\t\tstub_list:             unsafe { nil } // will be set later\n\t\tstub_type:             stub_type\n\t\tid:                    id\n\t}\n}\n"
  },
  {
    "path": "src/analyzer/index/IndexSerializer.v",
    "content": "module index\n\nimport analyzer.psi\nimport bytes\n\npub struct IndexSerializer {\nmut:\n\ts bytes.Serializer\n}\n\npub fn (mut s IndexSerializer) serialize_index(index Index) {\n\ts.s.write_string(index.version)\n\ts.s.write_i64(index.updated_at.unix())\n\ts.serialize_file_indexes(index.per_file.data)\n}\n\npub fn (mut s IndexSerializer) serialize_file_indexes(indexes map[string]FileIndex) {\n\ts.s.write_int(indexes.len)\n\tfor _, index in indexes {\n\t\ts.serialize_file_index(index)\n\t}\n}\n\npub fn (mut s IndexSerializer) serialize_file_index(index FileIndex) {\n\ts.s.write_u8(u8(index.kind))\n\ts.s.write_i64(index.file_last_modified)\n\n\ts.serialize_stub_list(index.stub_list)\n\ts.serialize_stub_index_sink(index.sink)\n}\n\npub fn (mut s IndexSerializer) serialize_stub_index_sink(sink &psi.StubIndexSink) {\n\ts.s.write_int(sink.data.len)\n\tfor key, datum in sink.data {\n\t\ts.s.write_int(key)\n\t\ts.serialize_stub_index_sink_map(datum)\n\t}\n\n\ts.s.write_int(sink.imported_modules.len)\n\tfor module_ in sink.imported_modules {\n\t\ts.s.write_string(module_)\n\t}\n}\n\npub fn (mut s IndexSerializer) serialize_stub_index_sink_map(sink_map map[string][]psi.StubId) {\n\ts.s.write_int(sink_map.len)\n\tfor key, stub_ids in sink_map {\n\t\ts.s.write_string(key)\n\t\ts.s.write_int(stub_ids.len)\n\t\tfor id in stub_ids {\n\t\t\ts.s.write_int(id)\n\t\t}\n\t}\n}\n\npub fn (mut s IndexSerializer) serialize_stub_list(list psi.StubList) {\n\ts.s.write_string(list.path)\n\ts.s.write_string(list.module_fqn)\n\ts.s.write_int(list.child_map.len)\n\tfor id, children in list.child_map {\n\t\ts.s.write_int(id)\n\t\ts.s.write_int(children.len)\n\t\tfor child in children {\n\t\t\ts.s.write_int(child)\n\t\t}\n\t}\n\n\t// serialize stubs as array\n\ts.s.write_int(list.index_map.len)\n\tfor stub in list.index_map.values() {\n\t\ts.serialize_stub(stub)\n\t}\n}\n\npub fn (mut s IndexSerializer) serialize_stub(stub psi.StubBase) {\n\ts.s.write_string(stub.text)\n\ts.s.write_string(stub.comment)\n\ts.s.write_string(stub.receiver)\n\ts.s.write_string(stub.additional)\n\ts.s.write_string(stub.name)\n\n\ts.s.write_int(stub.identifier_text_range.line)\n\ts.s.write_int(stub.identifier_text_range.column)\n\ts.s.write_int(stub.identifier_text_range.end_line)\n\ts.s.write_int(stub.identifier_text_range.end_column)\n\n\ts.s.write_int(stub.text_range.line)\n\ts.s.write_int(stub.text_range.column)\n\ts.s.write_int(stub.text_range.end_line)\n\ts.s.write_int(stub.text_range.end_column)\n\n\ts.s.write_int(stub.parent_id)\n\ts.s.write_u8(u8(stub.stub_type))\n\ts.s.write_int(stub.id)\n}\n"
  },
  {
    "path": "src/analyzer/index/IndexingRoot.v",
    "content": "module index\n\nimport time\nimport os\nimport sync\nimport runtime\nimport math\nimport loglib\nimport lsp\nimport crypto.md5\nimport analyzer.psi\nimport analyzer.parser\n\n// BuiltIndexStatus describes the status of the built index.\npub enum BuiltIndexStatus {\n\tfrom_cache   // index was loaded from cache\n\tfrom_scratch // index was built from scratch\n}\n\n// IndexingRootKind describes the type of root that is being indexed.\n// Same as `StubIndexKind`.\npub enum IndexingRootKind as u8 {\n\tstandard_library\n\tmodules\n\tstubs\n\tworkspace\n}\n\npub fn (k IndexingRootKind) readable_name() string {\n\treturn match k {\n\t\t.standard_library { 'Standard Library' }\n\t\t.modules { 'Modules' }\n\t\t.stubs { 'Stubs' }\n\t\t.workspace { 'Workspace' }\n\t}\n}\n\n// IndexingRoot encapsulates the logic of indexing/reindexing a particular root of the file system.\n//\n// Separation into separate roots is necessary in order to process the standard library and user code separately.\n@[noinit]\npub struct IndexingRoot {\npub:\n\troot string           // root that is indexed\n\tkind IndexingRootKind // type of root that is indexed\npub mut:\n\tcache_dir  string    // path to the directory where the index is stored\n\tupdated_at time.Time // when the index was last updated\n\tindex      Index     // index itself\n\tcache_file string    // path to the file where the index is stored\n\tneed_save  bool      // whether the index needs to be saved\n\tno_save    bool      // for tests\n}\n\n// new_indexing_root creates a new indexing root with the given root and kind.\npub fn new_indexing_root(root string, kind IndexingRootKind, cache_dir string) &IndexingRoot {\n\tcache_file := 'v_analyzer_index_${md5.hexhash(root)}'\n\treturn &IndexingRoot{\n\t\troot:       root\n\t\tkind:       kind\n\t\tcache_dir:  cache_dir\n\t\tcache_file: cache_file\n\t}\n}\n\nfn (mut i IndexingRoot) cache_file() string {\n\treturn os.join_path(i.cache_dir, i.cache_file)\n}\n\npub fn (mut i IndexingRoot) load_index() ! {\n\tnow := time.now()\n\tif !os.exists(i.cache_file()) {\n\t\tloglib.with_fields({\n\t\t\t'root': i.root\n\t\t}).info('Index not found, start indexing')\n\t\treturn IndexNotFoundError{}\n\t}\n\n\tdata := os.read_bytes(i.cache_file()) or {\n\t\tloglib.with_fields({\n\t\t\t'file':  i.cache_file()\n\t\t\t'error': err.str()\n\t\t}).error('Failed to read index')\n\t\treturn IndexNotFoundError{}\n\t}\n\ti.index.decode(data) or {\n\t\tif err is IndexVersionMismatchError {\n\t\t\tloglib.info('Index version mismatch')\n\t\t} else {\n\t\t\tloglib.with_fields({\n\t\t\t\t'file':  i.cache_file()\n\t\t\t\t'error': err.str()\n\t\t\t}).error('Error load index')\n\t\t}\n\t\treturn NeedReindexedError{}\n\t}\n\tloglib.info('Loaded index in ${time.since(now)}')\n}\n\npub fn (mut i IndexingRoot) save_index() ! {\n\tif !i.need_save || i.no_save {\n\t\treturn\n\t}\n\ti.need_save = false\n\n\tdata := i.index.encode()\n\tos.write_file_array(i.cache_file(), data) or {\n\t\tloglib.with_fields({\n\t\t\t'file':  i.cache_file()\n\t\t\t'error': err.str()\n\t\t}).error('Failed to write analyzer index file')\n\t\treturn err\n\t}\n}\n\n// need_index returns true if the file needs to be indexed.\n//\n// We deliberately do not index some of test files to speed up the indexing and searching process.\nfn (mut _ IndexingRoot) need_index(path string) bool {\n\tif path.ends_with('.vsh') {\n\t\treturn true\n\t}\n\n\tif !path.ends_with('.v') {\n\t\treturn false\n\t}\n\n\treturn !path.contains('/tests/') && !path.contains('/slow_tests/')\n\t\t&& !path.contains('/.vmodules/cache/')\n\t\t&& !path.contains('/builtin/wasm/') // TODO: index this folder too\n\t\t&& !path.contains('/builtin/js/') // TODO: index this folder too\n\t\t&& !path.contains('/builtin/linux_bare/') // TODO: index this folder too\n\t\t&& !path.ends_with('.js.v') && !path.contains('/.git/') && !path.ends_with('_test.v')\n}\n\npub fn (mut i IndexingRoot) index() BuiltIndexStatus {\n\tnow := time.now()\n\n\tloglib.with_fields({\n\t\t'root': i.root\n\t}).info('Indexing root')\n\n\tif _ := i.load_index() {\n\t\tloglib.with_duration(time.since(now)).info('Index loaded from cache')\n\t\treturn .from_cache\n\t}\n\n\tfile_chan := chan string{cap: 1000}\n\tcache_chan := chan FileIndex{cap: 1000}\n\n\tspawn fn [mut i, file_chan] () {\n\t\tpath := i.root\n\t\tos.walk(path, fn [mut i, file_chan] (path string) {\n\t\t\tif i.need_index(path) {\n\t\t\t\tfile_chan <- path\n\t\t\t}\n\t\t})\n\n\t\tfile_chan.close()\n\t}()\n\n\tspawn i.spawn_indexing_workers(cache_chan, file_chan)\n\n\tmut caches := []FileIndex{cap: 100}\n\tfor {\n\t\tcache := <-cache_chan or { break }\n\t\tcaches << cache\n\t}\n\n\tfor cache in caches {\n\t\ti.index.per_file.data[cache.path()] = cache\n\t}\n\n\ti.updated_at = time.now()\n\ti.need_save = true\n\n\tloglib.with_duration(time.since(now)).info('Indexing finished')\n\treturn .from_scratch\n}\n\npub fn (mut i IndexingRoot) index_file(path string, content string, mut p parser.Parser) !FileIndex {\n\tlast_modified := os.file_last_mod_unix(path)\n\tres := p.parse_code(content)\n\tpsi_file := psi.new_psi_file(path, res.tree, content)\n\tmodule_fqn := psi.module_qualified_name(psi_file, i.root)\n\n\tmut cache := FileIndex{\n\t\tkind:               i.kind\n\t\tfile_last_modified: last_modified\n\t\tsink:               &psi.StubIndexSink{\n\t\t\tkind:      unsafe { psi.StubIndexLocationKind(u8(i.kind)) }\n\t\t\tstub_list: unsafe { nil }\n\t\t}\n\t\tstub_list:          unsafe { nil }\n\t}\n\tstub_tree := build_stub_tree(psi_file, i.root)\n\n\tstub_type := psi.StubbedElementType{}\n\tmut stub_list := stub_tree.root.stub_list\n\tstub_list.module_fqn = module_fqn\n\tstub_list.path = path\n\n\tcache.sink.imported_modules = stub_tree.get_imported_modules()\n\n\tstubs := stub_list.index_map.values()\n\tfor stub in stubs {\n\t\tcache.sink.stub_id = stub.id\n\t\tcache.sink.stub_list = stub.stub_list\n\t\tstub_type.index_stub(stub, mut cache.sink)\n\t}\n\tcache.stub_list = stub_list\n\n\tunsafe { res.tree.free() }\n\treturn cache\n}\n\npub fn (mut i IndexingRoot) spawn_indexing_workers(cache_chan chan FileIndex, file_chan chan string) {\n\tmut wg := sync.new_waitgroup()\n\tcpus := runtime.nr_cpus()\n\tworkers := math.max(cpus - 4, 1)\n\twg.add(workers)\n\tfor j := 0; j < workers; j++ {\n\t\tspawn fn [file_chan, mut wg, mut i, cache_chan] () {\n\t\t\tmut p := parser.Parser.new()\n\t\t\tdefer { p.free() }\n\t\t\tfor {\n\t\t\t\tfilepath := <-file_chan or { break }\n\t\t\t\tcontent := os.read_file(filepath) or {\n\t\t\t\t\tloglib.with_fields({\n\t\t\t\t\t\t'uri':   lsp.document_uri_from_path(filepath).str()\n\t\t\t\t\t\t'error': err.str()\n\t\t\t\t\t}).error('Error reading file for index')\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tcache_chan <- i.index_file(filepath, content, mut p) or {\n\t\t\t\t\tloglib.with_fields({\n\t\t\t\t\t\t'uri':   lsp.document_uri_from_path(filepath).str()\n\t\t\t\t\t\t'error': err.str()\n\t\t\t\t\t}).error('Error indexing file')\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twg.done()\n\t\t}()\n\t}\n\n\twg.wait()\n\tcache_chan.close()\n}\n\n// ensure_indexed checks the index for freshness and re-indexes files if they have changed since the last indexing.\npub fn (mut i IndexingRoot) ensure_indexed() {\n\tnow := time.now()\n\n\tloglib.with_fields({\n\t\t'root': i.root\n\t}).info('Ensuring indexed root')\n\n\treindex_files_chan := chan string{cap: 1000}\n\tcache_chan := chan FileIndex{cap: 1000}\n\n\tspawn fn [reindex_files_chan, mut i] () {\n\t\tfor filepath, datum in i.index.per_file.data {\n\t\t\tlast_modified := os.file_last_mod_unix(filepath)\n\t\t\tif last_modified > datum.file_last_modified {\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'uri': lsp.document_uri_from_path(filepath).str()\n\t\t\t\t}).info('File was modified, reindexing')\n\t\t\t\ti.index.per_file.data.delete(filepath)\n\t\t\t\treindex_files_chan <- filepath\n\t\t\t}\n\t\t}\n\n\t\treindex_files_chan.close()\n\t}()\n\n\tspawn i.spawn_indexing_workers(cache_chan, reindex_files_chan)\n\n\tmut caches := []FileIndex{cap: 100}\n\tfor {\n\t\tcache := <-cache_chan or { break }\n\t\tcaches << cache\n\t}\n\n\tfor cache in caches {\n\t\ti.index.per_file.data[cache.path()] = cache\n\t}\n\n\tif caches.len > 0 {\n\t\ti.index.updated_at = time.now()\n\t\ti.need_save = true\n\t}\n\n\tloglib.with_duration(time.since(now)).info('Reindexing finished')\n}\n\npub fn (mut i IndexingRoot) mark_as_dirty(filepath string, new_content string) ! {\n\tif filepath !in i.index.per_file.data {\n\t\t// file does not belong to this index\n\t\treturn\n\t}\n\n\tloglib.with_fields({\n\t\t'uri': lsp.document_uri_from_path(filepath).str()\n\t}).info('Marking document as dirty')\n\ti.index.per_file.data.delete(filepath)\n\n\tmut p := parser.Parser.new()\n\tdefer { p.free() }\n\tres := i.index_file(filepath, new_content, mut p) or {\n\t\treturn error('Error indexing dirty ${filepath}: ${err}')\n\t}\n\ti.index.per_file.data[filepath] = res\n\ti.index.updated_at = time.now()\n\ti.need_save = true\n\ti.save_index() or { return err }\n\n\tloglib.with_fields({\n\t\t'uri': lsp.document_uri_from_path(filepath).str()\n\t}).info('Finished reindexing document')\n}\n\npub fn (mut i IndexingRoot) add_file(filepath string, content string) !FileIndex {\n\tloglib.with_fields({\n\t\t'uri': lsp.document_uri_from_path(filepath).str()\n\t}).info('Adding new document')\n\n\tmut p := parser.Parser.new()\n\tdefer { p.free() }\n\tres := i.index_file(filepath, content, mut p) or {\n\t\treturn error('Error indexing added ${filepath}: ${err}')\n\t}\n\ti.index.per_file.data[filepath] = res\n\ti.index.updated_at = time.now()\n\ti.need_save = true\n\ti.save_index() or { return err }\n\n\tloglib.with_fields({\n\t\t'uri': lsp.document_uri_from_path(filepath).str()\n\t}).info('Finished indexing added document')\n\n\tif isnil(res.sink) {\n\t\treturn error('Sink of added file is nil')\n\t}\n\n\treturn res\n}\n\npub fn (mut i IndexingRoot) rename_file(old string, new string) !FileIndex {\n\tcache := i.index.per_file.rename_file(old, new) or {\n\t\treturn error('cannot find file index after rename, most likely rename was failed')\n\t}\n\ti.need_save = true\n\ti.save_index() or { return err }\n\tif isnil(cache.sink) {\n\t\treturn error('Sink of renamed file is nil')\n\t}\n\treturn cache\n}\n\npub fn (mut i IndexingRoot) remove_file(path string) !FileIndex {\n\tcache := i.index.per_file.remove_file(path) or {\n\t\treturn error('cannot find file index after remove, most likely remove was failed')\n\t}\n\ti.need_save = true\n\ti.save_index() or { return err }\n\tif isnil(cache.sink) {\n\t\treturn error('Sink of removed file is nil')\n\t}\n\treturn cache\n}\n\npub fn (i &IndexingRoot) contains(path string) bool {\n\treturn path.starts_with(i.root)\n}\n"
  },
  {
    "path": "src/analyzer/index/IndexingRoot_test.v",
    "content": "module index\n\nfn test_git_files_do_not_need_indexed() {\n\tmut ir := new_indexing_root('.', .workspace, '/tmp')\n\tassert !ir.need_index('./.git/some_file.v')\n}\n\nfn test_v_test_files_do_not_need_indexed() {\n\tmut ir := new_indexing_root('.', .workspace, '/tmp')\n\tassert !ir.need_index('some_file_test.v')\n}\n"
  },
  {
    "path": "src/analyzer/index/PerFileIndex.v",
    "content": "module index\n\nimport analyzer.psi\n\n// PerFileIndex describes the cache of a group of files in the index.\npub struct PerFileIndex {\npub mut:\n\tdata map[string]FileIndex\n}\n\npub fn (p &PerFileIndex) get_sinks() []psi.StubIndexSink {\n\tmut res := []psi.StubIndexSink{cap: p.data.len}\n\tfor _, cache in p.data {\n\t\tif !isnil(cache.sink) {\n\t\t\tres << *cache.sink\n\t\t}\n\t}\n\treturn res\n}\n\npub fn (mut p PerFileIndex) rename_file(old string, new string) ?FileIndex {\n\tif old == new {\n\t\treturn none\n\t}\n\tif mut cache := p.data[old] {\n\t\tcache.stub_list.path = new\n\t\tp.data[new] = cache\n\t\tp.data.delete(old)\n\t\treturn cache\n\t}\n\n\treturn none\n}\n\npub fn (mut p PerFileIndex) remove_file(path string) ?FileIndex {\n\tif mut cache := p.data[path] {\n\t\tp.data.delete(path)\n\t\treturn cache\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/index/README.md",
    "content": "## Description\n\n`index` module describes index and indexing operations.\n"
  },
  {
    "path": "src/analyzer/index/StubTree.v",
    "content": "module index\n\nimport strings\nimport loglib\nimport analyzer.psi\n\n// StubTree represents a tree of stubs for a file.\n// This tree, unlike the AST, contains the nodes whose data we want to serialize to\n// speed up the startup of the server.\n// Such nodes implement the `psi.StubBasedPsiElement` interface.\n//\n// Unlike AST, `StubTree` trees are quite small, so they can be easily saved and fully loaded\n// into RAM without taking up a lot of space.\n//\n// With the help of `StubTree`, stub indexes are also built, which allow us to quickly find\n// the necessary elements in the workspace or standard library.\n// See `StubbedElementType.index_stub()`.\npub struct StubTree {\n\troot &psi.StubBase\n}\n\npub fn (tree &StubTree) print() {\n\tmut sb := strings.new_builder(100)\n\tmut p := StubTreePrinter{\n\t\tsb: &sb\n\t}\n\tp.print_stub(tree.root, 0)\n\tloglib.trace(sb.str())\n}\n\npub fn (tree &StubTree) print_to(mut sb strings.Builder) {\n\tmut p := StubTreePrinter{\n\t\tsb: unsafe { &sb }\n\t}\n\tp.print_stub(tree.root, 0)\n}\n\npub fn (tree &StubTree) get_imported_modules() []string {\n\tmut result := []string{}\n\tchildren := tree.root.children_stubs()\n\tfor child in children {\n\t\tif child.stub_type() == .import_list {\n\t\t\tdeclarations := child.children_stubs()\n\t\t\tfor declaration in declarations {\n\t\t\t\timport_spec := declaration.first_child() or { continue }\n\t\t\t\timport_path := import_spec.first_child() or { continue }\n\t\t\t\tif import_path.stub_type() == .import_path {\n\t\t\t\t\tresult << import_path.text()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\npub fn build_stub_tree(file &psi.PsiFile, indexing_root string) &StubTree {\n\tmut walker := psi.new_tree_walker(file.tree.root_node())\n\tdefer { walker.free() }\n\n\tstub_root := psi.new_root_stub(file.path())\n\tmodule_fqn := psi.module_qualified_name(file, indexing_root)\n\n\tif walker.current_node() != none {\n\t\tbuild_stub_tree_recurse(mut walker, file, stub_root, module_fqn, false)\n\t}\n\n\treturn &StubTree{\n\t\troot: stub_root\n\t}\n}\n\nfn build_stub_tree_recurse(mut tw psi.TreeWalker, file &psi.PsiFile, parent &psi.StubBase, module_fqn string, build_for_all_children bool) {\n\tnode := tw.current_node() or { return }\n\tnode_type := node.type_name\n\n\tstub_type := psi.node_type_to_stub_type(node_type)\n\tis_stubbable := stub_type != .root || psi.node_is_type(node_type)\n\n\tmut effective_parent := unsafe { parent }\n\tmut should_traverse_children := true\n\tmut pass_down_build_all := false\n\n\tif is_stubbable || build_for_all_children {\n\t\tpsi_element := psi.create_element(node, file)\n\t\telement_type := psi.StubbedElementType{}\n\n\t\tif stub := element_type.create_stub(psi_element, parent, module_fqn) {\n\t\t\teffective_parent = unsafe { stub }\n\t\t\tif node_type == .qualified_type {\n\t\t\t\tpass_down_build_all = true\n\t\t\t}\n\t\t}\n\t}\n\n\tif should_traverse_children {\n\t\tif tw.to_first_child() {\n\t\t\tfor {\n\t\t\t\tbuild_stub_tree_recurse(mut tw, file, effective_parent, module_fqn,\n\n\t\t\t\t\tbuild_for_all_children || pass_down_build_all)\n\n\t\t\t\tif !tw.next_sibling() {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\ttw.to_parent()\n\t\t}\n\t}\n}\n\nstruct NodeInfo {\n\tnode   psi.PsiElement\n\tparent &psi.StubBase\n}\n\npub fn build_stub_tree_iterative(file &psi.PsiFile, mut nodes []NodeInfo) &StubTree {\n\troot := file.root()\n\tstub_root := psi.new_root_stub(file.path())\n\n\tnodes = nodes[..0].clone()\n\tnodes << NodeInfo{\n\t\tnode:   root\n\t\tparent: stub_root\n\t}\n\n\telement_type := psi.StubbedElementType{}\n\n\tfor nodes.len > 0 {\n\t\tnode := nodes.pop()\n\t\tthis_parent_stub := node.parent\n\n\t\tparent_stub := if node.node is psi.StubBasedPsiElement {\n\t\t\tif stub := element_type.create_stub(node.node as psi.PsiElement, this_parent_stub, '') {\n\t\t\t\tstub\n\t\t\t} else {\n\t\t\t\tthis_parent_stub\n\t\t\t}\n\t\t} else {\n\t\t\tthis_parent_stub\n\t\t}\n\n\t\tfor child in node.node.children() {\n\t\t\tnodes << NodeInfo{\n\t\t\t\tnode:   child\n\t\t\t\tparent: parent_stub\n\t\t\t}\n\t\t}\n\t}\n\treturn &StubTree{\n\t\troot: stub_root\n\t}\n}\n\npub struct StubTreePrinter {\nmut:\n\tsb &strings.Builder\n}\n\npub fn (mut p StubTreePrinter) print_stub(stub psi.StubElement, indent int) {\n\tfor i := 0; i < indent; i++ {\n\t\tp.sb.write_string('  ')\n\t}\n\tp.sb.write_string(stub.stub_type().str())\n\n\ttext_range := stub.text_range()\n\tp.sb.write_string(' at ')\n\tp.sb.write_string((text_range.line + 1).str())\n\n\ttext := stub.text()\n\tif text.len != 0 {\n\t\tp.sb.write_string(' ')\n\t\tp.sb.write_string('\"')\n\t\tp.sb.write_string(text)\n\t\tp.sb.write_string('\"')\n\t}\n\tp.sb.write_string('\\n')\n\n\tfor child in stub.children_stubs() {\n\t\tp.print_stub(child, indent + 1)\n\t}\n}\n"
  },
  {
    "path": "src/analyzer/lang/utils.v",
    "content": "module lang\n\nimport analyzer.psi\nimport analyzer.psi.types\n\npub fn get_zero_value_for(typ types.Type) string {\n\treturn match typ {\n\t\ttypes.PrimitiveType {\n\t\t\tmatch typ.name {\n\t\t\t\t'bool' { 'false' }\n\t\t\t\t'rune' { '`0`' }\n\t\t\t\t'char', 'u8' { '0' }\n\t\t\t\t'voidptr', 'byteptr', 'charptr', 'nil' { 'unsafe { nil }' }\n\t\t\t\t'f32', 'f64' { '0.0' }\n\t\t\t\telse { '0' }\n\t\t\t}\n\t\t}\n\t\ttypes.StructType {\n\t\t\tmatch typ.name() {\n\t\t\t\t'string' { \"''\" }\n\t\t\t\telse { typ.readable_name() + '{}' }\n\t\t\t}\n\t\t}\n\t\ttypes.ArrayType {\n\t\t\treturn '[]'\n\t\t}\n\t\ttypes.FixedArrayType {\n\t\t\treturn '[]!'\n\t\t}\n\t\ttypes.MapType {\n\t\t\treturn '{}'\n\t\t}\n\t\ttypes.ChannelType {\n\t\t\treturn 'chan ${typ.inner.readable_name()}{}'\n\t\t}\n\t\ttypes.FunctionType {\n\t\t\treturn '${typ.readable_name()} {}'\n\t\t}\n\t\ttypes.AliasType {\n\t\t\treturn get_zero_value_for(typ.inner)\n\t\t}\n\t\ttypes.GenericInstantiationType {\n\t\t\treturn get_zero_value_for(typ.inner)\n\t\t}\n\t\ttypes.InterfaceType, types.PointerType {\n\t\t\treturn 'unsafe { nil }'\n\t\t}\n\t\ttypes.OptionType {\n\t\t\treturn 'none'\n\t\t}\n\t\ttypes.ResultType {\n\t\t\tif !typ.no_inner {\n\t\t\t\treturn get_zero_value_for(typ.inner)\n\t\t\t}\n\n\t\t\treturn \"error('')\"\n\t\t}\n\t\telse {\n\t\t\treturn '0'\n\t\t}\n\t}\n}\n\npub fn is_same_module(context psi.PsiElement, element psi.PsiElement) bool {\n\tcontext_file := context.containing_file() or { return false }\n\telement_file := element.containing_file() or { return false }\n\tcontext_module_fqn := context_file.module_fqn()\n\telement_module_fqn := element_file.module_fqn()\n\treturn context_module_fqn == element_module_fqn\n}\n"
  },
  {
    "path": "src/analyzer/parser/README.md",
    "content": "## Description\n\n`parser` module provides way to parse V code to AST.\n\nInput may be provided in a variety of forms (see the various `parser_*` functions)\nOutput is an abstract syntax tree (AST) representing the V source.\n\nThe parser accepts a larger language than is syntactically permitted by the V spec,\nfor simplicity, and for improved robustness in the presence of syntax errors.\n"
  },
  {
    "path": "src/analyzer/parser/batch.v",
    "content": "module parser\n\nimport sync\n\npub fn parse_batch_files(files []string, count_workers int) []ParseResult {\n\teffective_workers := if files.len < count_workers {\n\t\tfiles.len\n\t} else {\n\t\tcount_workers\n\t}\n\n\tfile_chan := chan string{cap: 1000}\n\tresult_chan := chan ParseResult{cap: 1000}\n\n\tspawn fn [file_chan, files] () {\n\t\tfor file in files {\n\t\t\tfile_chan <- file\n\t\t}\n\t\tfile_chan.close()\n\t}()\n\n\tspawn spawn_parser_workers(result_chan, file_chan, effective_workers)\n\n\tmut results := []ParseResult{cap: 100}\n\tfor {\n\t\tresult := <-result_chan or { break }\n\t\tresults << result\n\t}\n\treturn results\n}\n\nfn spawn_parser_workers(result_chan chan ParseResult, file_chan chan string, count_workers int) {\n\tmut wg := sync.new_waitgroup()\n\twg.add(count_workers)\n\n\tfor i := 0; i < count_workers; i++ {\n\t\tspawn fn [file_chan, mut wg, result_chan] () {\n\t\t\tmut p := Parser.new()\n\t\t\tdefer { p.free() }\n\t\t\tfor {\n\t\t\t\tfilepath := <-file_chan or { break }\n\t\t\t\tmut result := p.parse_file(filepath) or { continue }\n\t\t\t\tresult.path = filepath\n\t\t\t\tresult_chan <- result\n\t\t\t}\n\t\t\twg.done()\n\t\t}()\n\t}\n\n\twg.wait()\n\tresult_chan.close()\n}\n"
  },
  {
    "path": "src/analyzer/parser/parser.v",
    "content": "module parser\n\nimport tree_sitter_v.bindings\nimport os\n\n// ParseResult represents the result of a parsing operation.\npub struct ParseResult {\npub:\n\ttree        &bindings.Tree[bindings.NodeType] = unsafe { nil } // Resulting tree or nil if the source could not be parsed.\n\tsource_text string // Source code.\npub mut:\n\tpath string // Path of the file that was parsed.\n}\n\n// Source represent the possible types of V source code to parse.\ntype Source = []u8 | string\n\n// Parser is a wrapper around the Tree-sitter V parser.\npub struct Parser {\nmut:\n\tbinding_parser &bindings.Parser[bindings.NodeType] = unsafe { nil }\n}\n\n// new creates a new Parser instance.\npub fn Parser.new() &Parser {\n\tmut bp := bindings.new_parser[bindings.NodeType](bindings.type_factory)\n\tbp.set_language(bindings.language)\n\treturn &Parser{\n\t\tbinding_parser: bp\n\t}\n}\n\n// free frees the Tree-sitter parser.\npub fn (p &Parser) free() {\n\tunsafe {\n\t\tp.binding_parser.free()\n\t}\n}\n\n// parse_file parses a V source file and returns the corresponding `tree_sitter.Tree` and `Rope`.\n// If the file could not be read, an error is returned.\n// If the file was read successfully, but could not be parsed, the result\n// is a partially AST.\n//\n// Example:\n// ```\n// import parser\n//\n// fn main() {\n//  mut p := parser.Parser.new()\n//  res := p.parse_file('foo.v') or {\n//     eprintln('Error: could not parse file: ${err}')\n//     return\n//   }\n//   println(res.tree)\n// }\n// ```\npub fn (mut p Parser) parse_file(filename string) !ParseResult {\n\tcontent := os.read_file(filename) or { return error('could not read file ${filename}: ${err}') }\n\tmut res := p.parse_source(content)\n\tres.path = filename\n\treturn res\n}\n\n// parse_source parses a V code and returns the corresponding `tree_sitter.Tree` and `Rope`.\n// Unlike `parse_file`, `parse_source` uses the source directly, without reading it from a file.\n// See `parser.Source` for the possible types of `source`.\n//\n// Example:\n// ```\n// import parser\n//\n// fn main() {\n//   mut p := parser.Parser.new()\n//   res := p.parse_source('fn main() { println(\"Hello, World!\") }') or {\n//     eprintln('Error: could not parse source: ${err}')\n//     return\n//   }\n//   println(res.tree)\n// }\n// ```\npub fn (mut p Parser) parse_source(source Source) ParseResult {\n\tcode := match source {\n\t\tstring {\n\t\t\tsource\n\t\t}\n\t\t[]u8 {\n\t\t\tsource.str()\n\t\t}\n\t}\n\n\treturn p.parse_code(code)\n}\n\n// parse_code parses a V code and returns the corresponding `tree_sitter.Tree` and `Rope`.\n// Unlike `parse_file` and `parse_source`, `parse_code` don't return an error since\n// the source is always valid.\npub fn (mut p Parser) parse_code(code string) ParseResult {\n\ttree := p.binding_parser.parse_string(source: code)\n\treturn ParseResult{\n\t\ttree:        tree\n\t\tsource_text: code\n\t}\n}\n\n// parse_code_with_tree parses a V code and returns the corresponding `tree_sitter.Tree` and `Rope`.\n// This tree can be used to reparse the code with a some changes.\n// This is useful for incremental parsing.\n//\n// Unlike `parse_file` and `parse_source`, `parse_code` don't return an error since\n// the source is always valid.\n//\n// Example:\n// ```\n// import parser\n//\n// fn main() {\n//   mut p := parser.Parser.new()\n//   code := 'fn main() { println(\"Hello, World!\") }'\n//   res := p.parse_code_with_tree(code, unsafe { nil })\n//   println(res.tree)\n//   // some changes in code\n//   code2 := 'fn foo() { println(\"Hello, World!\") }'\n//   res2 = p.parse_code_with_tree(code2, res.tree)\n//   println(res2.tree\n// }\npub fn (mut p Parser) parse_code_with_tree(code string, old_tree &bindings.Tree[bindings.NodeType]) ParseResult {\n\traw_tree := if isnil(old_tree) { unsafe { nil } } else { old_tree.raw_tree }\n\ttree := p.binding_parser.parse_string(source: code, tree: raw_tree)\n\treturn ParseResult{\n\t\ttree:        tree\n\t\tsource_text: code\n\t}\n}\n"
  },
  {
    "path": "src/analyzer/psi/Argument.v",
    "content": "module psi\n\npub struct Argument {\n\tPsiElementImpl\n}\n"
  },
  {
    "path": "src/analyzer/psi/ArrayCreation.v",
    "content": "module psi\n\npub struct ArrayCreation {\n\tPsiElementImpl\n\tis_fixed bool\n}\n\npub fn (n ArrayCreation) expressions() []PsiElement {\n\tchildren := n.children()\n\treturn children.filter(it.element_type() != .unknown)\n}\n"
  },
  {
    "path": "src/analyzer/psi/AstNode.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub fn (node AstNode) parent_of_type(typ bindings.NodeType) ?AstNode {\n\tmut res := node\n\tfor {\n\t\tres = res.parent()?\n\t\tif res.type_name == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/Attribute.v",
    "content": "module psi\n\npub struct Attribute {\n\tPsiElementImpl\n}\n\nfn (_ &Attribute) stub() {}\n\npub fn (n Attribute) expressions() []src.analyzer.psi.PsiElement {\n\tif stub := n.get_stub() {\n\t\treturn stub.get_children_by_type(.attribute_expression).get_psi()\n\t}\n\n\treturn n.find_children_by_type(.attribute_expression)\n}\n\npub fn (n Attribute) keys() []string {\n\texpressions := n.expressions()\n\tif expressions.len == 0 {\n\t\treturn []\n\t}\n\n\treturn expressions.map(fn (expr PsiElement) string {\n\t\tif expr is AttributeExpression {\n\t\t\treturn expr.value()\n\t\t}\n\n\t\treturn ''\n\t}).filter(it != '')\n}\n"
  },
  {
    "path": "src/analyzer/psi/AttributeExpression.v",
    "content": "module psi\n\npub struct AttributeExpression {\n\tPsiElementImpl\n}\n\npub fn (n &AttributeExpression) value() string {\n\tif stub := n.get_stub() {\n\t\tif first_child := stub.first_child() {\n\t\t\treturn first_child.text()\n\t\t}\n\t\treturn ''\n\t}\n\n\tif first_child := n.first_child() {\n\t\tif first_child is ValueAttribute {\n\t\t\treturn first_child.value()\n\t\t}\n\t}\n\n\treturn ''\n}\n\nfn (_ &AttributeExpression) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/Attributes.v",
    "content": "module psi\n\npub struct Attributes {\n\tPsiElementImpl\n}\n\nfn (_ &Attributes) stub() {}\n\npub fn (n Attributes) attributes() []PsiElement {\n\treturn n.find_children_by_type_or_stub(.attribute)\n}\n"
  },
  {
    "path": "src/analyzer/psi/AttributesOwner.v",
    "content": "module psi\n\npub interface AttributesOwner {\n\tattributes() []PsiElement\n}\n"
  },
  {
    "path": "src/analyzer/psi/BinaryExpression.v",
    "content": "module psi\n\npub struct BinaryExpression {\n\tPsiElementImpl\n}\n\npub fn (n BinaryExpression) operator() string {\n\toperator_element := n.find_child_by_name('operator') or { return '' }\n\treturn operator_element.get_text()\n}\n\npub fn (n BinaryExpression) left() ?PsiElement {\n\treturn n.find_child_by_name('left')\n}\n\npub fn (n BinaryExpression) right() ?PsiElement {\n\treturn n.find_child_by_name('right')\n}\n"
  },
  {
    "path": "src/analyzer/psi/Block.v",
    "content": "module psi\n\npub struct Block {\n\tPsiElementImpl\n}\n\npub fn (b Block) last_expression() ?PsiElement {\n\tstatements := b.find_children_by_type(.simple_statement)\n\tif statements.len == 0 {\n\t\treturn none\n\t}\n\treturn statements.last().first_child()\n}\n\npub fn (b Block) process_declarations(mut processor PsiScopeProcessor, last_parent PsiElement) bool {\n\tstatements := b.find_children_by_type(.simple_statement)\n\tfor statement in statements {\n\t\tif statement.is_equal(last_parent) {\n\t\t\treturn true\n\t\t}\n\n\t\tfirst_child := statement.first_child() or { continue }\n\n\t\tif first_child is VarDeclaration {\n\t\t\tfor var in first_child.vars() {\n\t\t\t\tif !processor.execute(var) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "src/analyzer/psi/CallExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct CallExpression {\n\tPsiElementImpl\n}\n\nfn (c &CallExpression) get_type() types.Type {\n\treturn infer_type(c)\n}\n\nfn (c &CallExpression) caller_type() types.Type {\n\tref_expression := c.ref_expression() or { return types.unknown_type }\n\tif qualifier := ref_expression.qualifier() {\n\t\treturn infer_type(qualifier)\n\t}\n\treturn types.unknown_type\n}\n\npub fn (c CallExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n\npub fn (c CallExpression) ref_expression() ?ReferenceExpressionBase {\n\tif selector_expr := c.find_child_by_type(.selector_expression) {\n\t\tif selector_expr is ReferenceExpressionBase {\n\t\t\treturn selector_expr\n\t\t}\n\t} else if ref_expr := c.find_child_by_type(.reference_expression) {\n\t\tif ref_expr is ReferenceExpressionBase {\n\t\t\treturn ref_expr\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (c CallExpression) resolve() ?PsiElement {\n\texpr := c.ref_expression()?\n\n\tif expr is ReferenceExpressionBase {\n\t\tresolved := expr.resolve()?\n\t\treturn resolved\n\t}\n\n\treturn none\n}\n\npub fn (c CallExpression) parameter_index_on_offset(offset u32) int {\n\targument_list := c.find_child_by_type(.argument_list) or { return -1 }\n\tcommas := argument_list.children().filter(it.get_text() == ',')\n\tcount_commas_before := commas.filter(it.node().start_byte() < offset).len\n\treturn count_commas_before\n}\n\npub fn (c CallExpression) arguments() []PsiElement {\n\targument_list := c.find_child_by_type(.argument_list) or { return [] }\n\targuments := argument_list.find_children_by_type(.argument)\n\tmut exprs := []PsiElement{cap: arguments.len}\n\tfor argument in arguments {\n\t\texprs << argument.first_child() or { continue }\n\t}\n\treturn exprs\n}\n\npub fn (c CallExpression) is_json_decode() bool {\n\treturn c.has_child_of_type(.special_argument_list)\n}\n\npub fn (c &CallExpression) get_json_decode_type() types.Type {\n\tlist := c.find_child_by_type(.special_argument_list) or { return types.unknown_type }\n\ttyp := list.find_child_by_type(.plain_type) or { return types.unknown_type }\n\tmut visited := map[string]types.Type{}\n\treturn TypeInferer{}.convert_type(typ, mut visited)\n}\n\nfn (c &CallExpression) type_arguments() ?&GenericTypeArguments {\n\ttype_parameters := c.find_child_by_name('type_parameters')?\n\tif type_parameters is GenericTypeArguments {\n\t\treturn type_parameters\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/Comment.v",
    "content": "module psi\n\npub struct LineComment {\n\tPsiElementImpl\n}\n\npub struct BlockComment {\n\tPsiElementImpl\n}\n"
  },
  {
    "path": "src/analyzer/psi/CompileTimeIfExpression.v",
    "content": "module psi\n\npub struct CompileTimeIfExpression {\n\tPsiElementImpl\n}\n\npub fn (n CompileTimeIfExpression) block() ?&Block {\n\tblock := n.find_child_by_type(.block)?\n\tif block is Block {\n\t\treturn block\n\t}\n\treturn none\n}\n\npub fn (n CompileTimeIfExpression) else_branch() ?PsiElement {\n\treturn n.find_child_by_type(.else_branch)?.last_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/ConstantDeclaration.v",
    "content": "module psi\n\npub struct ConstantDeclaration {\n\tPsiElementImpl\n}\n\npub fn (n ConstantDeclaration) constants() []PsiElement {\n\treturn n.find_children_by_type(.const_definition)\n}\n"
  },
  {
    "path": "src/analyzer/psi/ConstantDefinition.v",
    "content": "module psi\n\nimport analyzer.parser\nimport analyzer.psi.types\n\npub struct ConstantDefinition {\n\tPsiElementImpl\n}\n\npub fn (c &ConstantDefinition) is_public() bool {\n\tmodifiers := c.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\npub fn (c &ConstantDefinition) get_type() types.Type {\n\texpr := c.expression() or { return types.unknown_type }\n\tres := infer_type(expr)\n\tif c.stub_based() {\n\t\tif mut file := expr.containing_file() {\n\t\t\tfile.free()\n\t\t}\n\t}\n\treturn res\n}\n\nfn (c &ConstantDefinition) identifier() ?PsiElement {\n\treturn c.find_child_by_type(.identifier)\n}\n\npub fn (c ConstantDefinition) identifier_text_range() TextRange {\n\tif stub := c.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := c.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (c ConstantDefinition) name() string {\n\tif stub := c.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := c.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (c ConstantDefinition) doc_comment() string {\n\tif stub := c.get_stub() {\n\t\treturn stub.comment\n\t}\n\tparent := c.parent() or { return '' }\n\treturn extract_doc_comment(parent)\n}\n\npub fn (c ConstantDefinition) visibility_modifiers() ?&VisibilityModifiers {\n\tif c.stub_based() {\n\t\tmodifiers := c.prev_sibling_of_type(.visibility_modifiers)?\n\t\tif modifiers is VisibilityModifiers {\n\t\t\treturn modifiers\n\t\t}\n\t\treturn none\n\t}\n\n\tdecl := c.parent()?\n\tmodifiers := decl.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (c &ConstantDefinition) expression() ?PsiElement {\n\tif stub := c.get_stub() {\n\t\tfile := c.containing_file() or { return none }\n\t\t// pretty hacky but it works\n\t\tmut p := parser.Parser.new()\n\t\tdefer { p.free() }\n\t\tres := p.parse_code(stub.additional)\n\t\troot := res.tree.root_node()\n\t\tfirst_child := root.first_child()?\n\t\tnext_first_child := first_child.first_child()?\n\t\tsynthetic_file := new_psi_file(file.path, res.tree, res.source_text)\n\t\treturn create_element(AstNode(next_first_child), synthetic_file)\n\t}\n\treturn c.last_child()\n}\n\npub fn (_ ConstantDefinition) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/EmbeddedDefinition.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct EmbeddedDefinition {\n\tPsiElementImpl\n}\n\npub fn (n &EmbeddedDefinition) owner() ?PsiElement {\n\tif struct_ := n.parent_of_type(.struct_declaration) {\n\t\treturn struct_\n\t}\n\treturn n.parent_of_type(.interface_declaration)\n}\n\npub fn (n &EmbeddedDefinition) identifier_text_range() TextRange {\n\tif stub := n.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (n &EmbeddedDefinition) identifier() ?PsiElement {\n\tif qualified_type := n.find_child_by_type_or_stub(.qualified_type) {\n\t\treturn qualified_type.last_child_or_stub()\n\t}\n\tif generic_type := n.find_child_by_type_or_stub(.generic_type) {\n\t\treturn generic_type.first_child_or_stub()\n\t}\n\tif ref_expression := n.find_child_by_type_or_stub(.type_reference_expression) {\n\t\treturn ref_expression.first_child_or_stub()\n\t}\n\treturn none\n}\n\npub fn (n &EmbeddedDefinition) name() string {\n\tif stub := n.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := n.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (_ &EmbeddedDefinition) is_public() bool {\n\treturn true\n}\n\npub fn (n &EmbeddedDefinition) get_type() types.Type {\n\treturn infer_type(n)\n}\n\nfn (_ &EmbeddedDefinition) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/EnumDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct EnumDeclaration {\n\tPsiElementImpl\n}\n\npub fn (e &EnumDeclaration) is_public() bool {\n\tmodifiers := e.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\npub fn (e &EnumDeclaration) get_type() types.Type {\n\tmodule_fqn := if file := e.containing_file() {\n\t\tstubs_index.get_module_qualified_name(file.path)\n\t} else {\n\t\t''\n\t}\n\treturn types.new_enum_type(e.name(), module_fqn)\n}\n\npub fn (e EnumDeclaration) identifier() ?PsiElement {\n\treturn e.find_child_by_type(.identifier)\n}\n\npub fn (e EnumDeclaration) identifier_text_range() TextRange {\n\tif stub := e.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := e.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (e EnumDeclaration) name() string {\n\tif stub := e.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := e.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (e EnumDeclaration) doc_comment() string {\n\tif stub := e.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(e)\n}\n\npub fn (e EnumDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := e.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (e EnumDeclaration) fields() []PsiElement {\n\tif stub := e.get_stub() {\n\t\treturn stub.get_children_by_type(.enum_field_definition).get_psi()\n\t}\n\n\treturn e.find_children_by_type(.enum_field_definition)\n}\n\npub fn (s &EnumDeclaration) attributes() []PsiElement {\n\tattributes := s.find_child_by_type_or_stub(.attributes) or { return [] }\n\tif attributes is Attributes {\n\t\treturn attributes.attributes()\n\t}\n\n\treturn []\n}\n\npub fn (e EnumDeclaration) is_flag() bool {\n\tattributes := e.attributes()\n\n\tfor attr in attributes {\n\t\tif attr is Attribute {\n\t\t\tkeys := attr.keys()\n\t\t\treturn 'flag' in keys\n\t\t}\n\t}\n\n\treturn false\n}\n\npub fn (_ EnumDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/EnumFieldDeclaration.v",
    "content": "@[translated]\nmodule psi\n\nimport analyzer.parser\nimport analyzer.psi.types\n\n__global enum_fields_cache = map[string]int{}\n\npub struct EnumFieldDeclaration {\n\tPsiElementImpl\n}\n\npub fn (_ &EnumFieldDeclaration) is_public() bool {\n\treturn true\n}\n\npub fn (f &EnumFieldDeclaration) doc_comment() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.comment\n\t}\n\n\tif comment := f.find_child_by_type(.line_comment) {\n\t\treturn comment.get_text().trim_string_left('//').trim(' \\t')\n\t}\n\n\treturn extract_doc_comment(f)\n}\n\npub fn (f &EnumFieldDeclaration) identifier() ?PsiElement {\n\treturn f.find_child_by_type(.identifier)\n}\n\npub fn (f EnumFieldDeclaration) identifier_text_range() TextRange {\n\tif stub := f.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := f.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (f &EnumFieldDeclaration) name() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := f.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (f &EnumFieldDeclaration) get_type() types.Type {\n\towner := f.owner() or { return types.unknown_type }\n\treturn owner.get_type()\n}\n\npub fn (f &EnumFieldDeclaration) fingerprint() string {\n\towner := f.owner() or { return '' }\n\tfile := f.containing_file() or { return '' }\n\treturn '${file.path}:${f.node.start_point()}${owner.name()}.${f.name()}'\n}\n\npub fn (f &EnumFieldDeclaration) value() ?PsiElement {\n\tif stub := f.get_stub() {\n\t\tif stub.additional.len == 0 {\n\t\t\treturn none\n\t\t}\n\n\t\tfile := f.containing_file() or { return none }\n\t\tmut p := parser.Parser.new()\n\t\tdefer { p.free() }\n\t\tres := p.parse_code(stub.additional)\n\t\troot := res.tree.root_node()\n\t\tfirst_child := root.first_child()?\n\t\tnext_first_child := first_child.first_child()?\n\t\tsynthetic_file := new_psi_file(file.path, res.tree, res.source_text)\n\t\treturn create_element(next_first_child, synthetic_file)\n\t}\n\n\treturn f.find_child_by_name('value')\n}\n\npub fn (f &EnumFieldDeclaration) owner() ?&EnumDeclaration {\n\tif stub := f.get_stub() {\n\t\tif parent := stub.parent_of_type(.enum_declaration) {\n\t\t\tif is_valid_stub(parent) {\n\t\t\t\tif psi := parent.get_psi() {\n\t\t\t\t\tif psi is EnumDeclaration {\n\t\t\t\t\t\treturn psi\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn none\n\t}\n\n\tpsi := f.parent_of_type(.enum_declaration)?\n\tif psi is EnumDeclaration {\n\t\treturn psi\n\t}\n\n\treturn none\n}\n\npub fn (f &EnumFieldDeclaration) value_presentation(with_dec_value bool) string {\n\towner := f.owner() or { return '' }\n\tcount_fields := owner.fields().len\n\tis_flag := owner.is_flag()\n\n\tvalue := f.get_value()\n\tif is_flag {\n\t\tmut bin := '0b' + f.add_padding('${value:b}', count_fields)\n\t\tif with_dec_value {\n\t\t\tbin += ' (${value})'\n\t\t}\n\t\treturn bin\n\t}\n\n\treturn value.str()\n}\n\npub fn (f &EnumFieldDeclaration) get_value() i64 {\n\tfingerprint := f.fingerprint()\n\tif value := enum_fields_cache[fingerprint] {\n\t\treturn value\n\t}\n\n\tvalue := f.get_value_impl()\n\tenum_fields_cache[fingerprint] = value\n\treturn value\n}\n\nfn (f &EnumFieldDeclaration) get_value_impl() i64 {\n\towner := f.owner() or { return 0 }\n\tis_flag := owner.is_flag()\n\n\tif !is_flag {\n\t\tif value := f.value() {\n\t\t\tval := f.calculate_value(value)\n\t\t\tif f.stub_based() {\n\t\t\t\tif mut file := value.containing_file() {\n\t\t\t\t\tfile.free()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif val != none {\n\t\t\t\treturn val\n\t\t\t}\n\t\t}\n\t}\n\n\tprev_field := f.prev_sibling_of_type(.enum_field_definition) or {\n\t\treturn if is_flag { 1 } else { 0 }\n\t}\n\tif prev_field is EnumFieldDeclaration {\n\t\tprev_value := prev_field.get_value()\n\t\tif is_flag {\n\t\t\treturn prev_value * 2\n\t\t}\n\t\treturn prev_value + 1\n\t}\n\treturn 0\n}\n\nfn (f &EnumFieldDeclaration) calculate_value(value PsiElement) ?i64 {\n\tif value is Literal {\n\t\treturn value.value()\n\t}\n\n\tif value is UnaryExpression {\n\t\tif value.operator() == '-' {\n\t\t\tif expr := value.expression() {\n\t\t\t\tif val := f.calculate_value(expr) {\n\t\t\t\t\treturn -val\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif value is BinaryExpression {\n\t\toperator := value.operator()\n\t\tif operator == '<<' {\n\t\t\tleft := value.left()?\n\t\t\tright := value.right()?\n\n\t\t\tleft_val := f.calculate_value(left)?\n\t\t\tright_val := f.calculate_value(right)?\n\n\t\t\tif left_val < 0 {\n\t\t\t\t// -1 << 1 is prohibited by V\n\t\t\t\treturn none\n\t\t\t}\n\n\t\t\treturn i64(u64(left_val) << right_val)\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn (_ EnumFieldDeclaration) add_padding(value string, size int) string {\n\tif size == -1 {\n\t\treturn value\n\t}\n\n\tlen := value.len\n\tif len >= size {\n\t\treturn value\n\t}\n\n\treturn '0'.repeat(size - len) + value\n}\n\npub fn (_ EnumFieldDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/FieldDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct FieldDeclaration {\n\tPsiElementImpl\n}\n\npub fn (f &FieldDeclaration) is_embedded_definition() bool {\n\treturn f.has_child_of_type(.embedded_definition)\n}\n\npub fn (f &FieldDeclaration) is_public() bool {\n\tif owner := f.owner() {\n\t\tif owner is InterfaceDeclaration {\n\t\t\treturn true // all interface fields are public by default\n\t\t}\n\t}\n\n\t_, is_pub := f.is_mutable_public()\n\treturn is_pub\n}\n\npub fn (f &FieldDeclaration) doc_comment() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.comment\n\t}\n\n\tif comment := f.find_child_by_type(.line_comment) {\n\t\treturn comment.get_text().trim_string_left('//').trim(' \\t')\n\t}\n\n\treturn extract_doc_comment(f)\n}\n\npub fn (f &FieldDeclaration) identifier() ?PsiElement {\n\treturn f.find_child_by_type(.identifier)\n}\n\npub fn (f FieldDeclaration) identifier_text_range() TextRange {\n\tif stub := f.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := f.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (f &FieldDeclaration) name() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := f.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (f &FieldDeclaration) get_type() types.Type {\n\treturn infer_type(f)\n}\n\npub fn (f &FieldDeclaration) owner() ?PsiElement {\n\tif struct_ := f.parent_of_type(.struct_declaration) {\n\t\treturn struct_\n\t}\n\treturn f.parent_of_type(.interface_declaration)\n}\n\npub fn (f &FieldDeclaration) scope() ?&StructFieldScope {\n\telement := f.sibling_of_type_backward(.struct_field_scope)?\n\tif element is StructFieldScope {\n\t\treturn element\n\t}\n\treturn none\n}\n\npub fn (f &FieldDeclaration) is_mutable_public() (bool, bool) {\n\tscope := f.scope() or { return false, false }\n\treturn scope.is_mutable_public()\n}\n\npub fn (_ FieldDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/FieldName.v",
    "content": "module psi\n\npub struct FieldName {\n\tPsiElementImpl\n}\n\npub fn (n FieldName) reference_expression() ?&ReferenceExpression {\n\tfirst_child := n.first_child()?\n\tif first_child is ReferenceExpression {\n\t\treturn first_child\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/ForStatement.v",
    "content": "module psi\n\npub struct ForStatement {\n\tPsiElementImpl\n}\n\npub fn (n ForStatement) var_definitions() []PsiElement {\n\tif range_clause := n.find_child_by_type(.range_clause) {\n\t\tvar_definition_list := range_clause.find_child_by_type(.var_definition_list) or {\n\t\t\treturn []\n\t\t}\n\t\treturn var_definition_list.find_children_by_type(.var_definition)\n\t}\n\n\tif for_clause := n.find_child_by_type(.for_clause) {\n\t\tinitializer := for_clause.first_child() or { return [] }\n\t\tif initializer.element_type() == .simple_statement {\n\t\t\tdecl := initializer.first_child() or { return [] }\n\t\t\tlist := decl.first_child() or { return [] }\n\t\t\tdefinition := list.first_child() or { return [] }\n\t\t\treturn [definition]\n\t\t}\n\t}\n\n\treturn []\n}\n"
  },
  {
    "path": "src/analyzer/psi/FunctionLiteral.v",
    "content": "module psi\n\npub struct FunctionLiteral {\n\tPsiElementImpl\n}\n\npub fn (f FunctionLiteral) signature() ?&Signature {\n\tsignature := f.find_child_by_type_or_stub(.signature)?\n\tif signature is Signature {\n\t\treturn signature\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/FunctionOrMethodDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct FunctionOrMethodDeclaration {\n\tPsiElementImpl\n}\n\npub fn (f &FunctionOrMethodDeclaration) generic_parameters() ?&GenericParameters {\n\tgeneric_parameters := f.find_child_by_type_or_stub(.generic_parameters)?\n\tif generic_parameters is GenericParameters {\n\t\treturn generic_parameters\n\t}\n\treturn none\n}\n\npub fn (f &FunctionOrMethodDeclaration) is_public() bool {\n\tmodifiers := f.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\nfn (f &FunctionOrMethodDeclaration) get_type() types.Type {\n\tsignature := f.signature() or { return types.unknown_type }\n\treturn signature.get_type()\n}\n\npub fn (f FunctionOrMethodDeclaration) identifier() ?PsiElement {\n\treturn f.find_child_by_type(.identifier)\n}\n\npub fn (f FunctionOrMethodDeclaration) identifier_text_range() TextRange {\n\tif stub := f.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := f.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (f FunctionOrMethodDeclaration) signature() ?&Signature {\n\tsignature := f.find_child_by_type_or_stub(.signature)?\n\tif signature is Signature {\n\t\treturn signature\n\t}\n\treturn none\n}\n\npub fn (f FunctionOrMethodDeclaration) name() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := f.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (f FunctionOrMethodDeclaration) doc_comment() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(f)\n}\n\npub fn (f FunctionOrMethodDeclaration) is_method() bool {\n\treturn f.has_child_of_type(.receiver)\n}\n\npub fn (f FunctionOrMethodDeclaration) receiver_type() types.Type {\n\treceiver := f.receiver() or { return types.unknown_type }\n\treturn receiver.get_type()\n}\n\npub fn (f FunctionOrMethodDeclaration) receiver() ?&Receiver {\n\telement := f.find_child_by_type_or_stub(.receiver)?\n\tif element is Receiver {\n\t\treturn element\n\t}\n\treturn none\n}\n\npub fn (f FunctionOrMethodDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := f.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (f FunctionOrMethodDeclaration) owner() ?PsiElement {\n\treceiver := f.receiver()?\n\ttyp := receiver.get_type()\n\tunwrapped := types.unwrap_generic_instantiation_type(types.unwrap_pointer_type(typ))\n\tif unwrapped is types.StructType {\n\t\treturn *find_struct(unwrapped.qualified_name())?\n\t}\n\tif unwrapped is types.AliasType {\n\t\treturn *find_alias(unwrapped.qualified_name())?\n\t}\n\treturn none\n}\n\npub fn (f FunctionOrMethodDeclaration) fingerprint() string {\n\tsignature := f.signature() or { return '' }\n\tcount_params := signature.parameters().len\n\thas_return_type := if _ := signature.result() { true } else { false }\n\treturn '${f.name()}:${count_params}:${has_return_type}'\n}\n\npub fn (_ FunctionOrMethodDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/GenericArgumentsOwner.v",
    "content": "module psi\n\npub interface GenericArgumentsOwner {\n\ttype_arguments() ?&GenericTypeArguments\n}\n"
  },
  {
    "path": "src/analyzer/psi/GenericParameter.v",
    "content": "module psi\n\n@[heap]\npub struct GenericParameter {\n\tPsiElementImpl\n}\n\npub fn (n &GenericParameter) identifier_text_range() TextRange {\n\tif stub := n.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (n &GenericParameter) identifier() ?PsiElement {\n\treturn n.find_child_by_type(.identifier)\n}\n\npub fn (n &GenericParameter) name() string {\n\tif stub := n.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := n.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (_ &GenericParameter) is_public() bool {\n\treturn true\n}\n\nfn (_ &GenericParameter) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/GenericParameters.v",
    "content": "module psi\n\nimport strings\n\npub struct GenericParameters {\n\tPsiElementImpl\n}\n\nfn (_ &GenericParameters) stub() {}\n\npub fn (n &GenericParameters) parameters() []PsiElement {\n\treturn n.find_children_by_type_or_stub(.generic_parameter)\n}\n\npub fn (n &GenericParameters) text_presentation() string {\n\tparameters := n.parameters()\n\tif parameters.len == 0 {\n\t\treturn ''\n\t}\n\tmut sb := strings.new_builder(5)\n\tsb.write_string('[')\n\tfor index, parameter in parameters {\n\t\tif parameter is PsiNamedElement {\n\t\t\tsb.write_string(parameter.name())\n\t\t}\n\t\tif index < parameters.len - 1 {\n\t\t\tsb.write_string(', ')\n\t\t}\n\t}\n\tsb.write_string(']')\n\treturn sb.str()\n}\n\npub fn (n &GenericParameters) parameter_names() []string {\n\tparameters := n.parameters()\n\tif parameters.len == 0 {\n\t\treturn []\n\t}\n\n\tmut result := []string{cap: parameters.len}\n\tfor parameter in parameters {\n\t\tif parameter is PsiNamedElement {\n\t\t\tresult << parameter.name()\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "src/analyzer/psi/GenericParametersOwner.v",
    "content": "module psi\n\npub interface GenericParametersOwner {\n\tgeneric_parameters() ?&GenericParameters\n}\n"
  },
  {
    "path": "src/analyzer/psi/GenericTypeArguments.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct GenericTypeArguments {\n\tPsiElementImpl\n}\n\npub fn (n GenericTypeArguments) types() []types.Type {\n\tplain_types := n.find_children_by_type(.plain_type)\n\n\tinferer := TypeInferer{}\n\tmut visited := map[string]types.Type{}\n\n\tmut arg_types := []types.Type{cap: plain_types.len}\n\tfor plain_type in plain_types {\n\t\targ_types << inferer.convert_type(plain_type, mut visited)\n\t}\n\n\treturn arg_types\n}\n"
  },
  {
    "path": "src/analyzer/psi/GenericTypeInferer.v",
    "content": "module psi\n\nimport analyzer.psi.types\nimport math\n\nstruct GenericTypeInferer {}\n\nfn (g &GenericTypeInferer) infer_generic_call(arg_owner GenericArgumentsOwner, params_owner GenericParametersOwner,\n\tresult_type types.Type) types.Type {\n\tgeneric_ts_map := g.infer_generic_ts_map(arg_owner, params_owner)\n\treturn result_type.substitute_generics(generic_ts_map)\n}\n\nfn (g &GenericTypeInferer) infer_generic_fetch(resolved PsiElement, expr SelectorExpression, generic_type types.Type) types.Type {\n\tif resolved !is FieldDeclaration {\n\t\treturn generic_type\n\t}\n\n\tqualifier := expr.qualifier() or { return generic_type }\n\tqualifier_type := infer_type(qualifier)\n\tinstantiation := g.extract_instantiation(qualifier_type) or { return generic_type }\n\n\tqualifier_specialization_map := g.infer_qualifier_generic_ts_map(instantiation)\n\tif qualifier_specialization_map.len == 0 {\n\t\treturn generic_type\n\t}\n\n\treturn generic_type.substitute_generics(qualifier_specialization_map)\n}\n\nfn (g &GenericTypeInferer) infer_generic_ts_map(arg_owner GenericArgumentsOwner, params_owner GenericParametersOwner) map[string]types.Type {\n\tif arg_owner is CallExpression {\n\t\tif ref_expression := arg_owner.ref_expression() {\n\t\t\tif qualifier := ref_expression.qualifier() {\n\t\t\t\tqualifier_type := infer_type(qualifier)\n\t\t\t\tif instantiation := g.extract_instantiation(qualifier_type) {\n\t\t\t\t\tqualifier_specialization_map := g.infer_qualifier_generic_ts_map(instantiation)\n\t\t\t\t\treturn g.infer_simple_generic_ts_map(arg_owner, params_owner,\n\t\t\t\t\t\tqualifier_specialization_map)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn g.infer_simple_generic_ts_map(arg_owner, params_owner, map[string]types.Type{})\n}\n\nfn (g &GenericTypeInferer) infer_simple_generic_ts_map(arg_owner GenericArgumentsOwner, params_owner GenericParametersOwner,\n\tadditional map[string]types.Type) map[string]types.Type {\n\tgeneric_parameters := g.generics_parameter_names(params_owner)\n\n\t// No data for inference, call is not generic.\n\tif generic_parameters.len == 0 && additional.len == 0 {\n\t\treturn map[string]types.Type{}\n\t}\n\n\t// foo[int, string]()\n\t//    ^^^^^^^^^^^^^ explicit generic arguments\n\t// Array[string]{}\n\t//      ^^^^^^^^ explicit generic arguments\n\tif generic_arguments := arg_owner.type_arguments() {\n\t\tgeneric_arguments_types := generic_arguments.types()\n\t\tif generic_arguments_types.len > 0 {\n\t\t\t// T: int\n\t\t\t// U: string\n\t\t\tmut mapping := map[string]types.Type{}\n\n\t\t\tfor i in 0 .. math.min(generic_parameters.len, generic_arguments_types.len) {\n\t\t\t\tmapping[generic_parameters[i]] = generic_arguments_types[i]\n\t\t\t}\n\n\t\t\tfor key, value in additional {\n\t\t\t\tmapping[key] = value\n\t\t\t}\n\n\t\t\treturn mapping\n\t\t}\n\t}\n\n\tif arg_owner is CallExpression {\n\t\tif params_owner is SignatureOwner {\n\t\t\targuments := arg_owner.arguments()\n\t\t\tsignature := params_owner.signature() or { return map[string]types.Type{} }\n\t\t\tparameters := signature.parameters()\n\n\t\t\targuments_types := arguments.map(infer_type(it))\n\t\t\tparameters_types := parameters.map(infer_type(it))\n\n\t\t\tmut reifier := GenericTypeReifier{}\n\t\t\treifier.reify_generic_ts(parameters_types, arguments_types)\n\n\t\t\tmut mapping := map[string]types.Type{}\n\t\t\tfor key, type_ in reifier.implicit_specialization_types_map {\n\t\t\t\tmapping[key] = type_\n\t\t\t}\n\n\t\t\tfor key, value in additional {\n\t\t\t\tmapping[key] = value\n\t\t\t}\n\n\t\t\treturn mapping\n\t\t}\n\t}\n\n\treturn additional\n}\n\nfn (g &GenericTypeInferer) infer_qualifier_generic_ts_map(typ types.GenericInstantiationType) map[string]types.Type {\n\tqualifier_generic_ts := g.extract_instantiation_ts(typ)\n\tif qualifier_generic_ts.len == 0 {\n\t\treturn map[string]types.Type{}\n\t}\n\n\tspecialization := typ.specialization\n\tmut mapping := map[string]types.Type{}\n\n\tfor i in 0 .. math.min(qualifier_generic_ts.len, specialization.len) {\n\t\tmapping[qualifier_generic_ts[i]] = specialization[i]\n\t}\n\n\treturn mapping\n}\n\nfn (g &GenericTypeInferer) extract_instantiation(typ types.Type) ?&types.GenericInstantiationType {\n\tif typ is types.GenericInstantiationType {\n\t\treturn typ\n\t}\n\n\tif typ is types.AliasType {\n\t\treturn g.extract_instantiation(typ.inner)\n\t}\n\n\tif typ is types.PointerType {\n\t\treturn g.extract_instantiation(typ.inner)\n\t}\n\n\tif typ is types.OptionType {\n\t\treturn g.extract_instantiation(typ.inner)\n\t}\n\n\tif typ is types.ResultType {\n\t\treturn g.extract_instantiation(typ.inner)\n\t}\n\n\treturn none\n}\n\npub fn (_ &GenericTypeInferer) extract_instantiation_ts(typ types.GenericInstantiationType) []string {\n\tinner_name := typ.inner.qualified_name()\n\telements := stubs_index.get_any_elements_by_name(inner_name)\n\tif elements.len == 0 {\n\t\treturn []\n\t}\n\n\tresolved := elements.first()\n\tif resolved is GenericParametersOwner {\n\t\tif generic_parameters := resolved.generic_parameters() {\n\t\t\treturn generic_parameters.parameter_names()\n\t\t}\n\t}\n\n\treturn []\n}\n\nfn (_ &GenericTypeInferer) generics_parameter_names(params_owner GenericParametersOwner) []string {\n\tparams := params_owner.generic_parameters() or { return [] }\n\treturn params.parameter_names()\n}\n"
  },
  {
    "path": "src/analyzer/psi/GenericTypeReifier.v",
    "content": "module psi\n\nimport analyzer.psi.types\nimport math\n\npub struct GenericTypeReifier {\nmut:\n\timplicit_specialization_types_map map[string]types.Type\n}\n\npub fn (mut g GenericTypeReifier) reify_generic_ts(param_types []types.Type, arg_types []types.Type) {\n\tfor i in 0 .. math.min(param_types.len, arg_types.len) {\n\t\tg.reify_generic_t(param_types[i], arg_types[i])\n\t}\n}\n\nfn (mut g GenericTypeReifier) reify_generic_t(param_type types.Type, arg_type types.Type) {\n\tif param_type is types.GenericType {\n\t\tg.implicit_specialization_types_map[param_type.name()] = arg_type\n\t}\n\n\tif param_type is types.GenericInstantiationType {\n\t\tif arg_type is types.GenericInstantiationType {\n\t\t\tfor i in 0 .. math.min(param_type.specialization.len, arg_type.specialization.len) {\n\t\t\t\tg.reify_generic_t(param_type.specialization[i], arg_type.specialization[i])\n\t\t\t}\n\t\t}\n\t}\n\n\tif param_type is types.MapType {\n\t\tif arg_type is types.MapType {\n\t\t\tg.reify_generic_t(param_type.key, arg_type.key)\n\t\t\tg.reify_generic_t(param_type.value, arg_type.value)\n\t\t}\n\t}\n\n\tif param_type is types.ResultType {\n\t\tif arg_type is types.ResultType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.OptionType {\n\t\tif arg_type is types.OptionType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.PointerType {\n\t\tif arg_type is types.PointerType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.ChannelType {\n\t\tif arg_type is types.ChannelType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.ArrayType {\n\t\tif arg_type is types.ArrayType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.FixedArrayType {\n\t\tif arg_type is types.FixedArrayType {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type.inner)\n\t\t} else {\n\t\t\tg.reify_generic_t(param_type.inner, arg_type)\n\t\t}\n\t}\n\n\tif param_type is types.FunctionType {\n\t\tif arg_type is types.FunctionType {\n\t\t\tfor i in 0 .. math.min(param_type.params.len, arg_type.params.len) {\n\t\t\t\tg.reify_generic_t(param_type.params[i], arg_type.params[i])\n\t\t\t}\n\n\t\t\tg.reify_generic_t(param_type.result, arg_type.result)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/analyzer/psi/GlobalVarDefinition.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct GlobalVarDefinition {\n\tPsiElementImpl\n}\n\nfn (_ &GlobalVarDefinition) stub() {}\n\npub fn (_ &GlobalVarDefinition) is_public() bool {\n\treturn true\n}\n\npub fn (n &GlobalVarDefinition) identifier() ?PsiElement {\n\tif node := n.find_child_by_name('name') {\n\t\treturn node\n\t}\n\treturn n.find_child_by_type(.identifier)\n}\n\npub fn (n &GlobalVarDefinition) identifier_text_range() TextRange {\n\tif stub := n.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (n &GlobalVarDefinition) name() string {\n\tif stub := n.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := n.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (n &GlobalVarDefinition) get_type() types.Type {\n\treturn infer_type(n)\n}\n"
  },
  {
    "path": "src/analyzer/psi/Identifier.v",
    "content": "module psi\n\npub struct Identifier {\n\tPsiElementImpl\n}\n\npub fn (i Identifier) value() string {\n\treturn i.get_text()\n}\n\npub fn (i Identifier) name() string {\n\treturn i.get_text()\n}\n\npub fn (i Identifier) qualifier() ?PsiElement {\n\tparent := i.parent()?\n\tif parent is SelectorExpression {\n\t\tleft := parent.left()?\n\t\tif left.is_equal(i) {\n\t\t\treturn none\n\t\t}\n\t\treturn left\n\t}\n\treturn none\n}\n\npub fn (i Identifier) reference() PsiReference {\n\tfile := i.containing_file()\n\treturn new_reference(file, i, false)\n}\n\npub fn (i Identifier) resolve() ?PsiElement {\n\tif parent := i.parent() {\n\t\tif parent is PsiNamedElement {\n\t\t\tif ident := parent.identifier() {\n\t\t\t\tif ident.is_equal(i) {\n\t\t\t\t\treturn parent as PsiElement\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn i.reference().resolve()\n}\n"
  },
  {
    "path": "src/analyzer/psi/IfExpression.v",
    "content": "module psi\n\npub struct IfExpression {\n\tPsiElementImpl\n}\n\npub fn (n IfExpression) var_definition() ?&VarDefinition {\n\tdecl := n.find_child_by_type(.var_declaration)?\n\tlist := decl.first_child()?\n\texpr := list.first_child()?\n\tif expr is VarDefinition {\n\t\treturn expr\n\t}\n\tif expr is MutExpression {\n\t\tvar := expr.last_child()?\n\t\tif var is VarDefinition {\n\t\t\treturn var\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (n IfExpression) block() ?&Block {\n\tblock := n.find_child_by_type(.block)?\n\treturn if block is Block { block } else { none }\n}\n\npub fn (n IfExpression) else_branch() ?PsiElement {\n\treturn n.find_child_by_type(.else_branch)?.last_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/ImportAlias.v",
    "content": "module psi\n\npub struct ImportAlias {\n\tPsiElementImpl\n}\n\nfn (n &ImportAlias) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/ImportDeclaration.v",
    "content": "module psi\n\npub struct ImportDeclaration {\n\tPsiElementImpl\n}\n\npub fn (n &ImportDeclaration) spec() ?&ImportSpec {\n\tspec := n.find_child_by_type(.import_spec)?\n\tif spec is ImportSpec {\n\t\treturn spec\n\t}\n\treturn none\n}\n\nfn (n &ImportDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/ImportList.v",
    "content": "module psi\n\npub struct ImportList {\n\tPsiElementImpl\n}\n\nfn (n &ImportList) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/ImportName.v",
    "content": "module psi\n\npub struct ImportName {\n\tPsiElementImpl\n}\n\nfn (n &ImportName) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/ImportPath.v",
    "content": "module psi\n\npub struct ImportPath {\n\tPsiElementImpl\n}\n\nfn (n &ImportPath) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/ImportSpec.v",
    "content": "module psi\n\npub struct ImportSpec {\n\tPsiElementImpl\n}\n\nfn (_ &ImportSpec) stub() {}\n\npub fn (_ &ImportSpec) is_public() bool {\n\treturn true\n}\n\nfn (n &ImportSpec) identifier_text_range() TextRange {\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\nfn (n &ImportSpec) identifier() ?PsiElement {\n\tlast_part := n.last_part()?\n\tif last_part is ImportName {\n\t\treturn last_part\n\t}\n\treturn none\n}\n\nfn (n &ImportSpec) name() string {\n\treturn n.import_name()\n}\n\npub fn (n &ImportSpec) qualified_name() string {\n\tpath := n.path() or { return '' }\n\treturn path.get_text()\n}\n\npub fn (n ImportSpec) alias() ?PsiElement {\n\treturn n.find_child_by_type_or_stub(.import_alias)\n}\n\npub fn (n ImportSpec) path() ?PsiElement {\n\treturn n.find_child_by_type_or_stub(.import_path)\n}\n\npub fn (n ImportSpec) last_part() ?PsiElement {\n\tpath := n.path()?\n\treturn path.last_child_or_stub()\n}\n\npub fn (n ImportSpec) import_name() string {\n\tif alias := n.alias() {\n\t\tif identifier := alias.last_child_or_stub() {\n\t\t\treturn identifier.get_text()\n\t\t}\n\t}\n\n\tif last_part := n.last_part() {\n\t\treturn last_part.get_text()\n\t}\n\n\treturn ''\n}\n\npub fn (n ImportSpec) alias_name() string {\n\tif alias := n.alias() {\n\t\tif identifier := alias.last_child() {\n\t\t\treturn identifier.get_text()\n\t\t}\n\t}\n\n\treturn ''\n}\n\npub fn (n ImportSpec) resolve_directory() string {\n\tfqn := n.qualified_name()\n\tif fqn == '' {\n\t\treturn ''\n\t}\n\n\treturn stubs_index.get_module_root(fqn)\n}\n\npub fn (n &ImportSpec) selective_list() ?&SelectiveImportList {\n\tlist := n.find_child_by_type_or_stub(.selective_import_list)?\n\tif list is SelectiveImportList {\n\t\treturn list\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/IndexExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct IndexExpression {\n\tPsiElementImpl\n}\n\nfn (c &IndexExpression) get_type() types.Type {\n\treturn infer_type(c)\n}\n\npub fn (c IndexExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/InterfaceDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct InterfaceDeclaration {\n\tPsiElementImpl\n}\n\npub fn (s &InterfaceDeclaration) generic_parameters() ?&GenericParameters {\n\tgeneric_parameters := s.find_child_by_type_or_stub(.generic_parameters)?\n\tif generic_parameters is GenericParameters {\n\t\treturn generic_parameters\n\t}\n\treturn none\n}\n\npub fn (s &InterfaceDeclaration) is_public() bool {\n\tmodifiers := s.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\npub fn (s &InterfaceDeclaration) module_name() string {\n\tfile := s.containing_file() or { return '' }\n\treturn stubs_index.get_module_qualified_name(file.path)\n}\n\npub fn (s &InterfaceDeclaration) get_type() types.Type {\n\treturn types.new_interface_type(s.name(), s.module_name())\n}\n\npub fn (s &InterfaceDeclaration) attributes() []PsiElement {\n\tattributes := s.find_child_by_type(.attributes) or { return [] }\n\tif attributes is Attributes {\n\t\treturn attributes.attributes()\n\t}\n\n\treturn []\n}\n\npub fn (s InterfaceDeclaration) identifier() ?PsiElement {\n\treturn s.find_child_by_type(.identifier)\n}\n\npub fn (s InterfaceDeclaration) identifier_text_range() TextRange {\n\tif stub := s.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := s.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (s InterfaceDeclaration) name() string {\n\tif stub := s.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := s.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (s InterfaceDeclaration) doc_comment() string {\n\tif stub := s.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(s)\n}\n\npub fn (s InterfaceDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := s.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (s InterfaceDeclaration) fields() []PsiElement {\n\tmut fields := s.own_fields()\n\n\tembedded_types := s.embedded_definitions()\n\t\t.map(types.unwrap_alias_type(it.get_type()))\n\t\t.filter(it is types.InterfaceType)\n\n\tfor embedded_type in embedded_types {\n\t\tif interface_ := find_interface(embedded_type.qualified_name()) {\n\t\t\tfields << interface_.fields()\n\t\t}\n\t}\n\n\treturn fields\n}\n\npub fn (s InterfaceDeclaration) own_fields() []PsiElement {\n\tfield_declarations := s.find_children_by_type_or_stub(.struct_field_declaration)\n\tmut result := []PsiElement{cap: field_declarations.len}\n\tfor field_declaration in field_declarations {\n\t\tif first_child := field_declaration.first_child_or_stub() {\n\t\t\tif first_child.element_type() != .embedded_definition {\n\t\t\t\tresult << field_declaration\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (s InterfaceDeclaration) embedded_definitions() []&EmbeddedDefinition {\n\tfield_declarations := s.find_children_by_type_or_stub(.struct_field_declaration)\n\tmut result := []&EmbeddedDefinition{cap: field_declarations.len}\n\tfor field_declaration in field_declarations {\n\t\tif embedded_definition := field_declaration.find_child_by_type_or_stub(.embedded_definition) {\n\t\t\tif embedded_definition is EmbeddedDefinition {\n\t\t\t\tresult << embedded_definition\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (s InterfaceDeclaration) methods() []PsiElement {\n\treturn s.find_children_by_type_or_stub(.interface_method_definition)\n}\n\npub fn (s InterfaceDeclaration) find_method(name string) ?&InterfaceMethodDeclaration {\n\tmethods := s.methods()\n\tfor method in methods {\n\t\tif method is InterfaceMethodDeclaration {\n\t\t\tif name == method.name() {\n\t\t\t\treturn method\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (_ InterfaceDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/InterfaceMethodDeclaration.v",
    "content": "module psi\n\npub struct InterfaceMethodDeclaration {\n\tPsiElementImpl\n}\n\npub fn (_ InterfaceMethodDeclaration) is_public() bool {\n\treturn true\n}\n\npub fn (m InterfaceMethodDeclaration) identifier() ?PsiElement {\n\treturn m.find_child_by_type(.identifier)\n}\n\npub fn (m InterfaceMethodDeclaration) identifier_text_range() TextRange {\n\tif stub := m.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := m.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (m InterfaceMethodDeclaration) signature() ?&Signature {\n\tsignature := m.find_child_by_type_or_stub(.signature)?\n\tif signature is Signature {\n\t\treturn signature\n\t}\n\treturn none\n}\n\npub fn (m InterfaceMethodDeclaration) name() string {\n\tif stub := m.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := m.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (m &InterfaceMethodDeclaration) owner() ?&InterfaceDeclaration {\n\tparent := m.parent_of_type(.interface_declaration)?\n\tif parent is InterfaceDeclaration {\n\t\treturn parent\n\t}\n\treturn none\n}\n\npub fn (m &InterfaceMethodDeclaration) scope() ?&StructFieldScope {\n\telement := m.sibling_of_type_backward(.struct_field_scope)?\n\tif element is StructFieldScope {\n\t\treturn element\n\t}\n\treturn none\n}\n\npub fn (m InterfaceMethodDeclaration) doc_comment() string {\n\tif stub := m.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(m)\n}\n\npub fn (m InterfaceMethodDeclaration) fingerprint() string {\n\tsignature := m.signature() or { return '' }\n\tcount_params := signature.parameters().len\n\thas_return_type := if _ := signature.result() { true } else { false }\n\treturn '${m.name()}:${count_params}:${has_return_type}'\n}\n\npub fn (_ InterfaceMethodDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/KeyedElement.v",
    "content": "module psi\n\npub struct KeyedElement {\n\tPsiElementImpl\n}\n\npub fn (n KeyedElement) field() ?&FieldName {\n\tfirst_child := n.first_child()?\n\tif first_child is FieldName {\n\t\treturn first_child\n\t}\n\treturn none\n}\n\npub fn (n KeyedElement) value() ?PsiElement {\n\treturn n.last_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/Literal.v",
    "content": "module psi\n\nimport strconv\nimport analyzer.psi.types\n\npub struct Literal {\n\tPsiElementImpl\n}\n\nfn (n &Literal) get_type() types.Type {\n\treturn infer_type(n)\n}\n\nfn (n &Literal) value() i64 {\n\ttext := n.get_text()\n\tif text.starts_with('0x') {\n\t\treturn strconv.parse_int(text[2..], 16, 64) or { 0 }\n\t} else if text.starts_with('0b') {\n\t\treturn strconv.parse_int(text[2..], 2, 64) or { 0 }\n\t} else if text.starts_with('0o') {\n\t\treturn strconv.parse_int(text[2..], 8, 64) or { 0 }\n\t}\n\n\treturn text.int()\n}\n"
  },
  {
    "path": "src/analyzer/psi/MapInitExpression.v",
    "content": "module psi\n\npub struct MapInitExpression {\n\tPsiElementImpl\n}\n\npub fn (n MapInitExpression) key_values() []PsiElement {\n\treturn n.find_children_by_type(.map_keyed_element)\n}\n"
  },
  {
    "path": "src/analyzer/psi/MapKeyedElement.v",
    "content": "module psi\n\npub struct MapKeyedElement {\n\tPsiElementImpl\n}\n\npub fn (n MapKeyedElement) key() ?PsiElement {\n\treturn n.first_child()\n}\n\npub fn (n MapKeyedElement) value() ?PsiElement {\n\treturn n.last_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/MatchExpression.v",
    "content": "module psi\n\npub struct MatchExpression {\n\tPsiElementImpl\n}\n\npub fn (n MatchExpression) expression() ?PsiElement {\n\treturn n.find_child_by_name('condition')\n}\n\npub fn (n MatchExpression) arms() []PsiElement {\n\tarms := n.find_child_by_type(.match_arms) or { return [] }\n\tmut arm_list := arms.find_children_by_type(.match_arm)\n\tarm_list << arms.find_children_by_type(.match_else_arm_clause)\n\treturn arm_list\n}\n\npub fn (n MatchExpression) else_branch() ?PsiElement {\n\treturn n.find_child_by_name('else_branch')\n}\n"
  },
  {
    "path": "src/analyzer/psi/ModuleClause.v",
    "content": "module psi\n\nimport os\n\npub struct ModuleClause {\n\tPsiElementImpl\n}\n\nfn (_ &ModuleClause) stub() {}\n\npub fn (_ &ModuleClause) is_public() bool {\n\treturn true\n}\n\nfn (n &ModuleClause) identifier() ?PsiElement {\n\treturn n.find_child_by_type(.identifier)\n}\n\npub fn (n &ModuleClause) identifier_text_range() TextRange {\n\tif stub := n.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (n ModuleClause) name() string {\n\tif stub := n.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := n.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn module_qualified_name(file &PsiFile, indexing_root string) string {\n\tmodule_name := file.module_name() or { '' }\n\tif module_name in ['main', 'builtin'] {\n\t\treturn module_name\n\t}\n\tif module_name == '' && file.is_test_file() {\n\t\treturn ''\n\t}\n\n\tmut root_dirs := [indexing_root]\n\n\tsrc_dir := os.join_path(indexing_root, 'src')\n\tif os.exists(src_dir) {\n\t\troot_dirs << src_dir\n\t}\n\n\troot_modules_dir := os.join_path(indexing_root, 'modules')\n\tif os.exists(root_modules_dir) {\n\t\troot_dirs << root_modules_dir\n\t}\n\n\tsrc_modules_dir := os.join_path(indexing_root, 'src', 'modules')\n\tif os.exists(src_modules_dir) {\n\t\troot_dirs << src_modules_dir\n\t}\n\n\tcontaining_dir := os.dir(file.path)\n\n\tmut module_names := []string{}\n\n\tmut dir := containing_dir\n\tfor dir != '' && dir !in root_dirs {\n\t\tmodule_names << os.file_name(dir)\n\t\tdir = os.dir(dir)\n\t}\n\n\tmodule_names.reverse_in_place()\n\n\tif module_names.len == 0 {\n\t\treturn module_name\n\t}\n\n\tif module_names.first() == 'builtin' {\n\t\tmodule_names = module_names[1..].clone()\n\t}\n\n\tif module_names.len != 0 && module_names.last() == module_name {\n\t\tmodule_names = module_names[..module_names.len - 1].clone()\n\t}\n\n\tif module_names.len >= 2 && module_names[module_names.len - 1] == 'src'\n\t\t&& module_names[module_names.len - 2] == module_name\n\t\t&& os.is_file(os.join_path(dir, module_names[0..module_names.len - 1].join(os.path_separator), 'v.mod')) {\n\t\tmodule_names = module_names[..module_names.len - 2].clone()\n\t}\n\n\tqualifier := module_names.join('.')\n\tif qualifier == '' {\n\t\treturn module_name\n\t}\n\n\tif module_name == '' {\n\t\treturn qualifier\n\t}\n\n\treturn qualifier + '.' + module_name\n}\n"
  },
  {
    "path": "src/analyzer/psi/MutExpression.v",
    "content": "module psi\n\npub struct MutExpression {\n\tPsiElementImpl\n}\n"
  },
  {
    "path": "src/analyzer/psi/MutabilityModifiers.v",
    "content": "module psi\n\npub struct MutabilityModifiers {\n\tPsiElementImpl\n}\n\npub fn (n MutabilityModifiers) is_mutable() bool {\n\tchildren := n.children()\n\treturn children.any(it.get_text() == 'mut')\n}\n"
  },
  {
    "path": "src/analyzer/psi/MutabilityOwner.v",
    "content": "module psi\n\npub interface MutabilityOwner {\n\tis_mutable() bool\n\tmutability_modifiers() ?&MutabilityModifiers\n}\n"
  },
  {
    "path": "src/analyzer/psi/OptionPropagationExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct OptionPropagationExpression {\n\tPsiElementImpl\n}\n\nfn (c &OptionPropagationExpression) get_type() types.Type {\n\treturn infer_type(c)\n}\n\npub fn (c OptionPropagationExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/OrBlockExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct OrBlockExpression {\n\tPsiElementImpl\n}\n\nfn (c &OrBlockExpression) get_type() types.Type {\n\treturn infer_type(c)\n}\n\npub fn (c OrBlockExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/ParameterDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct ParameterDeclaration {\n\tPsiElementImpl\n}\n\nfn (p &ParameterDeclaration) stub() {}\n\npub fn (_ &ParameterDeclaration) is_public() bool {\n\treturn true\n}\n\npub fn (p &ParameterDeclaration) get_type() types.Type {\n\treturn infer_type(p)\n}\n\npub fn (p &ParameterDeclaration) identifier() ?PsiElement {\n\treturn p.find_child_by_type(.identifier)\n}\n\npub fn (p &ParameterDeclaration) identifier_text_range() TextRange {\n\tif stub := p.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := p.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (p &ParameterDeclaration) name() string {\n\tif stub := p.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := p.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (p &ParameterDeclaration) mutability_modifiers() ?&MutabilityModifiers {\n\tmodifiers := p.find_child_by_type_or_stub(.mutability_modifiers)?\n\tif modifiers is MutabilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (p &ParameterDeclaration) is_mutable() bool {\n\tmods := p.mutability_modifiers() or { return false }\n\treturn mods.is_mutable()\n}\n"
  },
  {
    "path": "src/analyzer/psi/ParameterList.v",
    "content": "module psi\n\npub struct ParameterList {\n\tPsiElementImpl\n}\n\nfn (_ &ParameterList) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/PlainType.v",
    "content": "module psi\n\n@[heap]\npub struct PlainType {\n\tPsiElementImpl\n}\n\nfn (_ &PlainType) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/Position.v",
    "content": "module psi\n\npub struct Position {\npub:\n\tline      int\n\tcharacter int\n}\n"
  },
  {
    "path": "src/analyzer/psi/PrinterVisitor.v",
    "content": "module psi\n\nimport arrays\n\npub struct PrinterVisitor {\nmut:\n\tindent     int\n\tlines      []string\n\ttext_lines []string\n}\n\nfn (mut r PrinterVisitor) visit_element(element PsiElement) {\n\tif !r.visit_element_impl(element) {\n\t\treturn\n\t}\n\tmut child := element.first_child() or { return }\n\tr.indent += 1\n\tfor {\n\t\tchild.accept_mut(mut r)\n\t\tchild = child.next_sibling() or { break }\n\t}\n\tr.indent -= 1\n}\n\nfn (mut r PrinterVisitor) visit_element_impl(element PsiElement) bool {\n\tr.lines << '  '.repeat(r.indent) + '${element.node().type_name}'\n\tr.text_lines << '${element.get_text()}'\n\treturn true\n}\n\npub fn (r &PrinterVisitor) print() {\n\tmax_line_width := arrays.max(r.lines.map(it.len)) or { 0 }\n\tfor i, line in r.lines {\n\t\ttext_lines := r.text_lines[i].split_into_lines()\n\t\tif text_lines.len == 0 {\n\t\t\tprintln('<empty>')\n\t\t} else if text_lines.len == 1 {\n\t\t\tprintln(line + ' '.repeat(max_line_width - line.len) + ' | ' + r.text_lines[i])\n\t\t} else {\n\t\t\tprintln(line + ' '.repeat(max_line_width - line.len) + ' | ' + text_lines[0])\n\t\t\tfor j in 1 .. text_lines.len {\n\t\t\t\tprintln(' '.repeat(max_line_width) + ' | ' + text_lines[j].trim_string_left('  '))\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiDocCommentOwner.v",
    "content": "module psi\n\npub interface PsiDocCommentOwner {\n\tdoc_comment() string\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiElement.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub type ID = int\n\npub type AstNode = bindings.Node[bindings.NodeType]\n\npub interface PsiElement {\n\t// node returns the base node from Tree Sitter.\n\t// In stub-based elements, this might be a zero-value node.\n\tnode() AstNode\n\t// element_type returns the specific type of the element.\n\telement_type() bindings.NodeType\n\t// containing_file returns the file where the element is located.\n\t// Returns none if the element is synthetic or the file context is lost.\n\tcontaining_file() ?&PsiFile\n\t// is_equal returns true if the element represents the same underlying node/stub as other.\n\tis_equal(other PsiElement) bool\n\n\t// return the slot id of the stub, or non_stubbed_element if the element is not stub-based\n\tstub_id() StubId\n\t// return the stub associated with the element, or none if the element is not stub-based\n\tget_stub() ?&StubBase\n\t// stub_list return the stub list associated with the element, or none if the element is not stub-based\n\tstub_list() ?&StubList\n\n\t// text_range returns the range of the node in the source file.\n\ttext_range() TextRange\n\t// text_length returns the length of the node's text.\n\ttext_length() int\n\t// get_text returns the text of the node.\n\tget_text() string\n\t// text_matches returns true if the text of the node matches the specified value.\n\t// This method is more efficient than `get_text() == value`.\n\ttext_matches(value string) bool\n\n\t// parent returns the parent node.\n\t// If the node is the root, none is returned.\n\tparent() ?PsiElement\n\t// parent_nth returns the parent node at the specified nesting level.\n\t// `parent_nth(0)` is equivalent to `parent()`.\n\t// If no such node exists, none is returned.\n\tparent_nth(depth int) ?PsiElement\n\t// parent_of_type returns the parent node with the specified type.\n\t// If no such node exists, none is returned.\n\tparent_of_type(typ bindings.NodeType) ?PsiElement\n\t// parent_of_any_type returns the parent node with one of the specified types.\n\t// If no such node exists, none is returned.\n\tparent_of_any_type(types ...bindings.NodeType) ?PsiElement\n\t// parent_of_type_or_self returns the parent node with the specified type, or the\n\t// node itself if its type matches the specified one.\n\t// If no such node exists, none is returned.\n\tparent_of_type_or_self(typ bindings.NodeType) ?PsiElement\n\t// is_parent_of returns true if the passed node is a child of the given node.\n\tis_parent_of(element PsiElement) bool\n\t// inside returns true if the node is inside a node with the specified type.\n\tinside(typ bindings.NodeType) bool\n\n\t// children returns all child nodes.\n\tchildren() []PsiElement\n\t// named_children returns child nodes except unknown nodes.\n\tnamed_children() []PsiElement\n\t// first_child returns the first child node.\n\t// If the node has no children, none is returned.\n\tfirst_child() ?PsiElement\n\t// first_child_or_stub returns the first child node or stub.\n\t// If the node has no children or stub, none is returned.\n\tfirst_child_or_stub() ?PsiElement\n\t// last_child returns the last child of the node.\n\t// If the node has no children, none is returned.\n\tlast_child() ?PsiElement\n\t// last_child_or_stub returns the last child node or stub.\n\t// If the node has no children or stub, none is returned.\n\tlast_child_or_stub() ?PsiElement\n\n\t// next_sibling returns the next node at the same nesting level.\n\t// If the node is the last child node, none is returned.\n\tnext_sibling() ?PsiElement\n\t// next_sibling_or_stub returns the next node at the same nesting level or stub.\n\t// If the node is the last child node or stub, none is returned.\n\tnext_sibling_or_stub() ?PsiElement\n\t// prev_sibling returns the previous node at the same nesting level.\n\t// If the node is the first child node, none is returned.\n\tprev_sibling() ?PsiElement\n\t// prev_sibling_of_type returns the previous node at the same nesting level with the specified type.\n\t// If no such node exists, none is returned.\n\tprev_sibling_of_type(typ bindings.NodeType) ?PsiElement\n\t// prev_sibling_or_stub returns the previous node at the same nesting level or stub.\n\t// If the node is the first child node or stub, none is returned.\n\tprev_sibling_or_stub() ?PsiElement\n\t// sibling_of_type_backward returns the previous node at the same nesting level with the specified type.\n\t// If no such node exists, none is returned.\n\tsibling_of_type_backward(typ bindings.NodeType) ?PsiElement\n\n\t// find_element_at returns the leaf node at the specified position relative to the start of the node.\n\t// If the node is not found, none is returned.\n\tfind_element_at(offset u32) ?PsiElement\n\t// find_reference_at returns the reference node at the specified position relative to the start of the node.\n\t// If the node is not found, none is returned.\n\tfind_reference_at(offset u32) ?PsiElement\n\t// find_child_by_type returns the first child node with the specified type.\n\t// If no such node is found, none is returned.\n\tfind_child_by_type(typ bindings.NodeType) ?PsiElement\n\t// find_child_by_type_or_stub returns the first child node with the specified type or stub.\n\t// If no such node is found, none is returned.\n\tfind_child_by_type_or_stub(typ bindings.NodeType) ?PsiElement\n\t// find_child_by_name returns the first child node with the specified name.\n\t// If no such node is found, none is returned.\n\tfind_child_by_name(name string) ?PsiElement\n\t// find_children_by_type returns all child nodes with the specified type.\n\t// If no such nodes are found, an empty array is returned.\n\tfind_children_by_type(typ bindings.NodeType) []PsiElement\n\t// find_children_by_type_or_stub returns all child nodes with the specified type or stub.\n\t// If no such nodes are found, an empty array is returned.\n\tfind_children_by_type_or_stub(typ bindings.NodeType) []PsiElement\n\t// has_child_of_type returns true if the node has a child with the specified type.\n\thas_child_of_type(typ bindings.NodeType) bool\n\n\t// accept passes the element to the passed visitor.\n\taccept(visitor PsiElementVisitor)\n\t// accept_mut passes the element to the passed visitor.\n\t// Unlike `accept()`, this method uses a visitor that can mutate its state.\n\taccept_mut(mut visitor MutablePsiElementVisitor)\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiElementImpl.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub struct PsiElementImpl {\npub:\n\tnode            AstNode // base node from Tree Sitter\n\tcontaining_file ?&PsiFile\n\t// stubs related\n\tstub_id    StubId = non_stubbed_element\n\tstubs_list ?&StubList\n}\n\npub fn new_psi_node(containing_file ?&PsiFile, node AstNode) PsiElementImpl {\n\treturn PsiElementImpl{\n\t\tnode:            node\n\t\tcontaining_file: containing_file\n\t}\n}\n\nfn new_psi_node_from_stub(id StubId, stubs_list &StubList) PsiElementImpl {\n\treturn PsiElementImpl{\n\t\tnode:            AstNode{}\n\t\tcontaining_file: new_stub_psi_file(stubs_list.path, stubs_list)\n\t\tstub_id:         id\n\t\tstubs_list:      stubs_list\n\t}\n}\n\nfn (n &PsiElementImpl) is_valid_tree() bool {\n\tif n.stub_based() {\n\t\treturn true\n\t}\n\tfile := n.containing_file or { return true }\n\treturn !isnil(file.tree)\n}\n\npub fn (n &PsiElementImpl) stub_id() StubId {\n\treturn n.stub_id\n}\n\npub fn (n &PsiElementImpl) stub_based() bool {\n\treturn n.stubs_list != none\n}\n\npub fn (n &PsiElementImpl) get_stub() ?&StubBase {\n\tlist := n.stub_list()?\n\treturn list.get_stub(n.stub_id)\n}\n\npub fn (n &PsiElementImpl) stub_list() ?&StubList {\n\treturn n.stubs_list\n}\n\npub fn (n &PsiElementImpl) node() AstNode {\n\treturn n.node\n}\n\npub fn (n &PsiElementImpl) element_type() bindings.NodeType {\n\tif stub := n.get_stub() {\n\t\treturn stub.element_type()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn .unknown\n\t}\n\n\treturn n.node.type_name\n}\n\npub fn (n &PsiElementImpl) containing_file() ?&PsiFile {\n\tif list := n.stubs_list {\n\t\treturn new_stub_psi_file(list.path, list)\n\t}\n\n\treturn n.containing_file\n}\n\npub fn (n &PsiElementImpl) is_equal(other PsiElement) bool {\n\tif n.element_type() != other.element_type() {\n\t\treturn false\n\t}\n\n\tif n.text_range() != other.text_range() {\n\t\treturn false\n\t}\n\n\treturn n.get_text() == other.get_text()\n}\n\npub fn (n &PsiElementImpl) accept(visitor PsiElementVisitor) {\n\tvisitor.visit_element(n)\n}\n\npub fn (n &PsiElementImpl) accept_mut(mut visitor MutablePsiElementVisitor) {\n\tvisitor.visit_element(n)\n}\n\npub fn (n &PsiElementImpl) find_element_at(offset u32) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tstart_byte := if n.node.type_name == .source_file { u32(0) } else { n.node.start_byte() }\n\tabs_offset := start_byte + offset\n\tel := n.node.descendant_for_byte_range(abs_offset, abs_offset)?\n\treturn create_element(el, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) find_reference_at(offset u32) ?PsiElement {\n\telement := n.find_element_at(offset)?\n\tif element is Identifier {\n\t\tparent := element.parent()?\n\t\tif parent is ReferenceExpressionBase {\n\t\t\treturn parent as PsiElement\n\t\t}\n\t}\n\tif element is ReferenceExpressionBase {\n\t\treturn element as PsiElement\n\t}\n\treturn none\n}\n\npub fn (n &PsiElementImpl) parent() ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tif isnil(stub) {\n\t\t\treturn none\n\t\t}\n\n\t\tparent := stub.parent_stub()?\n\t\tif isnil(parent) {\n\t\t\treturn none\n\t\t}\n\n\t\tif parent.stub_type() == .root {\n\t\t\treturn none\n\t\t}\n\n\t\tif is_valid_stub(parent) {\n\t\t\treturn parent.get_psi()\n\t\t}\n\t\treturn none\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tparent := n.node.parent()?\n\treturn create_element(parent, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) parent_nth(depth int) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tparent := n.node.parent_nth(depth)?\n\treturn create_element(parent, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) parent_of_type(typ bindings.NodeType) ?PsiElement {\n\tmut res := PsiElement(n)\n\tfor {\n\t\tres = res.parent()?\n\t\tif res.element_type() == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &PsiElementImpl) parent_of_any_type(types ...bindings.NodeType) ?PsiElement {\n\tmut res := PsiElement(n)\n\tfor {\n\t\tres = res.parent()?\n\t\telement_type := res.element_type()\n\t\tif element_type in types {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &PsiElementImpl) inside(typ bindings.NodeType) bool {\n\tmut res := PsiElement(n)\n\tfor {\n\t\tres = res.parent() or { return false }\n\t\tif res.element_type() == typ {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\npub fn (n &PsiElementImpl) is_parent_of(element PsiElement) bool {\n\tif stub := n.get_stub() {\n\t\tif element_stub := element.get_stub() {\n\t\t\tif stub.stub_list.path != element_stub.stub_list.path {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tmut parent := element.parent() or { return false }\n\n\tfor {\n\t\tif parent.is_equal(n) {\n\t\t\treturn true\n\t\t}\n\t\tparent = parent.parent() or { break }\n\t}\n\n\treturn false\n}\n\npub fn (n &PsiElementImpl) sibling_of_type_backward(typ bindings.NodeType) ?PsiElement {\n\tmut res := PsiElement(n)\n\tfor {\n\t\tres = res.prev_sibling_or_stub()?\n\t\tif res.element_type() == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &PsiElementImpl) parent_of_type_or_self(typ bindings.NodeType) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tif n.node.type_name == typ {\n\t\treturn create_element(n.node, n.containing_file)\n\t}\n\tmut parent := n.parent()?\n\tif parent.element_type() == typ {\n\t\treturn parent\n\t}\n\n\tfor {\n\t\tparent = parent.parent()?\n\t\tif parent.element_type() == typ {\n\t\t\treturn parent\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &PsiElementImpl) children() []PsiElement {\n\tif stub := n.get_stub() {\n\t\tchildren := stub.children_stubs()\n\t\treturn children.get_psi()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn []\n\t}\n\n\tmut result := []PsiElement{}\n\tmut child := n.node.first_child() or { return [] }\n\tfor {\n\t\tresult << create_element(child, n.containing_file)\n\t\tchild = child.next_sibling() or { break }\n\t}\n\treturn result\n}\n\npub fn (n &PsiElementImpl) named_children() []PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn []\n\t}\n\n\tif stub := n.get_stub() {\n\t\tchildren := stub.children_stubs()\n\t\treturn children.get_psi()\n\t}\n\n\tmut result := []PsiElement{}\n\tmut child := n.node.first_child() or { return [] }\n\tfor {\n\t\tif child.type_name != .unknown {\n\t\t\tresult << create_element(child, n.containing_file)\n\t\t}\n\t\tchild = child.next_sibling() or { break }\n\t}\n\treturn result\n}\n\npub fn (n &PsiElementImpl) first_child() ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tchild := n.node.first_child()?\n\treturn create_element(child, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) first_child_or_stub() ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tchild := stub.first_child()?\n\t\treturn child.get_psi()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tchild := n.node.first_child()?\n\treturn create_element(child, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) last_child() ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\tchild := n.node.last_child()?\n\treturn create_element(child, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) last_child_or_stub() ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tchild := stub.last_child()?\n\t\treturn child.get_psi()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tchild := n.node.last_child()?\n\treturn create_element(child, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) next_sibling() ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tsibling := n.node.next_sibling()?\n\treturn create_element(sibling, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) next_sibling_or_stub() ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tsibling := stub.next_sibling()?\n\t\tif is_valid_stub(sibling) {\n\t\t\treturn sibling.get_psi()\n\t\t}\n\t\treturn none\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\treturn n.next_sibling()\n}\n\npub fn (n &PsiElementImpl) prev_sibling() ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tsibling := n.node.prev_sibling()?\n\treturn create_element(sibling, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) prev_sibling_of_type(typ bindings.NodeType) ?PsiElement {\n\tmut res := PsiElement(n)\n\tfor {\n\t\tres = res.prev_sibling_or_stub()?\n\t\tif res.element_type() == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &PsiElementImpl) prev_sibling_or_stub() ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tsibling := stub.prev_sibling()?\n\t\tif is_valid_stub(sibling) {\n\t\t\treturn sibling.get_psi()\n\t\t}\n\t\treturn none\n\t}\n\n\treturn n.prev_sibling()\n}\n\npub fn (n &PsiElementImpl) find_child_by_type(typ bindings.NodeType) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tast_node := n.node.first_node_by_type(typ)?\n\treturn create_element(ast_node, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) has_child_of_type(typ bindings.NodeType) bool {\n\tif stub := n.get_stub() {\n\t\treturn stub.has_child_of_type(node_type_to_stub_type(typ))\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn false\n\t}\n\n\tif _ := n.node.first_node_by_type(typ) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\npub fn (n &PsiElementImpl) find_child_by_type_or_stub(typ bindings.NodeType) ?PsiElement {\n\tif stub := n.get_stub() {\n\t\tchild := stub.get_child_by_type(node_type_to_stub_type(typ))?\n\t\treturn child.get_psi()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tast_node := n.node.first_node_by_type(typ)?\n\treturn create_element(ast_node, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) find_child_by_name(name string) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tast_node := n.node.child_by_field_name(name)?\n\treturn create_element(ast_node, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) find_children_by_type(typ bindings.NodeType) []PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn []\n\t}\n\n\tmut result := []PsiElement{}\n\tmut child := n.node.first_child() or { return [] }\n\tfor {\n\t\tif child.type_name == typ {\n\t\t\tresult << create_element(child, n.containing_file)\n\t\t}\n\t\tchild = child.next_sibling() or { break }\n\t}\n\treturn result\n}\n\npub fn (n &PsiElementImpl) find_children_by_type_or_stub(typ bindings.NodeType) []PsiElement {\n\tif stub := n.get_stub() {\n\t\treturn stub.get_children_by_type(node_type_to_stub_type(typ)).get_psi()\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn []\n\t}\n\n\tmut result := []PsiElement{}\n\tmut child := n.node.first_child() or { return [] }\n\tfor {\n\t\tif child.type_name == typ {\n\t\t\tresult << create_element(child, n.containing_file)\n\t\t}\n\t\tchild = child.next_sibling() or { break }\n\t}\n\treturn result\n}\n\npub fn (n &PsiElementImpl) find_last_child_by_type(typ bindings.NodeType) ?PsiElement {\n\tif !n.is_valid_tree() {\n\t\treturn none\n\t}\n\n\tast_node := n.node.last_node_by_type(typ)?\n\treturn create_element(ast_node, n.containing_file)\n}\n\npub fn (n &PsiElementImpl) get_text() string {\n\tif stub := n.get_stub() {\n\t\treturn stub.text\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn ''\n\t}\n\n\tif file := n.containing_file() {\n\t\treturn n.node.text(file.source_text)\n\t}\n\n\treturn ''\n}\n\npub fn (n &PsiElementImpl) text_matches(value string) bool {\n\tif stub := n.get_stub() {\n\t\treturn stub.text == value\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn false\n\t}\n\n\tif file := n.containing_file() {\n\t\treturn n.node.text_matches(file.source_text, value)\n\t}\n\n\treturn false\n}\n\npub fn (n &PsiElementImpl) text_range() TextRange {\n\tif stub := n.get_stub() {\n\t\treturn stub.text_range\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn TextRange{}\n\t}\n\n\treturn TextRange{\n\t\tline:       int(n.node.start_point().row)\n\t\tcolumn:     int(n.node.start_point().column)\n\t\tend_line:   int(n.node.end_point().row)\n\t\tend_column: int(n.node.end_point().column)\n\t}\n}\n\npub fn (n &PsiElementImpl) text_length() int {\n\tif stub := n.get_stub() {\n\t\trange := stub.text_range\n\t\treturn range.end_column - range.column\n\t}\n\n\tif !n.is_valid_tree() {\n\t\treturn 0\n\t}\n\n\treturn int(n.node.text_length())\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiElementVisitor.v",
    "content": "module psi\n\npub interface PsiElementVisitor {\n\tvisit_element(element PsiElement)\n\tvisit_element_impl(element PsiElement) bool\n}\n\npub interface MutablePsiElementVisitor {\nmut:\n\tvisit_element(element PsiElement)\n\tvisit_element_impl(element PsiElement) bool\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiFile.v",
    "content": "module psi\n\nimport lsp\nimport time\nimport utils\nimport loglib\nimport analyzer.parser\nimport tree_sitter_v.bindings\n\n@[heap]\npub struct PsiFile {\npub:\n\tpath      string\n\tstub_list &StubList = unsafe { nil }\npub mut:\n\ttree        &bindings.Tree[bindings.NodeType] = unsafe { nil }\n\tsource_text string\n\troot        PsiElement\n}\n\npub fn new_psi_file(path string, tree &bindings.Tree[bindings.NodeType], source_text string) &PsiFile {\n\tmut file := &PsiFile{\n\t\tpath:        path\n\t\ttree:        unsafe { tree }\n\t\tsource_text: source_text\n\t\tstub_list:   unsafe { nil }\n\t\troot:        unsafe { nil }\n\t}\n\tfile.root = create_element(AstNode(tree.root_node()), file)\n\treturn file\n}\n\npub fn new_stub_psi_file(path string, stub_list &StubList) &PsiFile {\n\treturn &PsiFile{\n\t\tpath:        path\n\t\ttree:        unsafe { nil }\n\t\tsource_text: ''\n\t\tstub_list:   stub_list\n\t\troot:        unsafe { nil }\n\t}\n}\n\n@[inline]\npub fn (p &PsiFile) is_stub_based() bool {\n\treturn isnil(p.tree)\n}\n\n@[inline]\npub fn (p &PsiFile) is_test_file() bool {\n\treturn p.path.ends_with('_test.v')\n}\n\n@[inline]\npub fn (p &PsiFile) is_shell_script() bool {\n\treturn p.path.ends_with('.vsh')\n}\n\n@[inline]\npub fn (p &PsiFile) index_sink() ?StubIndexSink {\n\treturn stubs_index.get_sink_for_file(p.path)\n}\n\npub fn (mut f PsiFile) reparse(new_code string, mut p parser.Parser) {\n\tnow := time.now()\n\tunsafe { f.tree.free() }\n\t// TODO: for some reason if we pass the old tree then trying to get the text\n\t// of the node gives the text at the wrong offset.\n\tres := p.parse_code_with_tree(new_code, unsafe { nil })\n\tf.tree = res.tree\n\tf.source_text = res.source_text\n\tf.root = create_element(AstNode(res.tree.root_node()), f)\n\n\tloglib.with_duration(time.since(now)).with_fields({\n\t\t'file':   f.path\n\t\t'length': f.source_text.len.str()\n\t}).info('Reparsed file')\n}\n\n@[inline]\npub fn (p &PsiFile) path() string {\n\treturn p.path\n}\n\n@[inline]\npub fn (p &PsiFile) uri() string {\n\treturn lsp.document_uri_from_path(p.path)\n}\n\n@[inline]\npub fn (p &PsiFile) text() string {\n\treturn p.source_text\n}\n\npub fn (mut p PsiFile) free() {\n\tif !isnil(p.tree) {\n\t\tunsafe { p.tree.free() }\n\t\tp.tree = unsafe { nil }\n\t}\n}\n\npub fn (p &PsiFile) symbol_at(range TextRange) u8 {\n\tlines := p.source_text.split_into_lines()\n\tline := lines[range.line] or { return 0 }\n\treturn line[range.column - 1] or { return 0 }\n}\n\npub fn (p &PsiFile) root() PsiElement {\n\tif p.is_stub_based() {\n\t\treturn p.stub_list.root().get_psi() or { return p.root }\n\t}\n\n\treturn p.root\n}\n\n@[inline]\npub fn (p &PsiFile) find_element_at(offset u32) ?PsiElement {\n\treturn p.root.find_element_at(offset)\n}\n\n@[inline]\npub fn (p &PsiFile) find_element_at_pos(pos Position) ?PsiElement {\n\toffset := utils.compute_offset(p.source_text, pos.line, pos.character)\n\treturn p.root.find_element_at(u32(offset))\n}\n\npub fn (p &PsiFile) find_reference_at(offset u32) ?ReferenceExpressionBase {\n\telement := p.find_element_at(offset)?\n\tif element is Identifier {\n\t\tparent := element.parent()?\n\t\tif parent is ReferenceExpressionBase {\n\t\t\treturn parent\n\t\t}\n\t}\n\tif element is ReferenceExpressionBase {\n\t\treturn element\n\t}\n\treturn none\n}\n\n@[inline]\npub fn (p &PsiFile) module_fqn() string {\n\treturn stubs_index.get_module_qualified_name(p.path)\n}\n\npub fn (p &PsiFile) module_name() ?string {\n\tmodule_clause := p.root().find_child_by_type_or_stub(.module_clause)?\n\n\tif module_clause is ModuleClause {\n\t\treturn module_clause.name()\n\t}\n\n\treturn none\n}\n\npub fn (p &PsiFile) module_clause() ?&ModuleClause {\n\tmodule_clause := p.root().find_child_by_type_or_stub(.module_clause)?\n\n\tif module_clause is ModuleClause {\n\t\treturn module_clause\n\t}\n\n\treturn none\n}\n\npub fn (p &PsiFile) get_imports() []ImportSpec {\n\tmut specs := []ImportSpec{}\n\n\tif p.is_stub_based() {\n\t\tfor _, stub in p.stub_list.index_map {\n\t\t\tif stub.stub_type == .import_spec {\n\t\t\t\tif element := stub.get_psi() {\n\t\t\t\t\tif element is ImportSpec {\n\t\t\t\t\t\tspecs << element\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tmut walker := new_psi_tree_walker(p.root())\n\t\tdefer { walker.free() }\n\n\t\tfor {\n\t\t\tchild := walker.next() or { break }\n\t\t\tif child is ImportSpec {\n\t\t\t\tspecs << child\n\t\t\t}\n\t\t}\n\t}\n\n\treturn specs\n}\n\npub fn (p &PsiFile) resolve_import_spec(name string) ?ImportSpec {\n\tspecs := p.resolve_import_specs(name)\n\tif specs.len > 0 {\n\t\treturn specs.first()\n\t}\n\treturn none\n}\n\npub fn (p &PsiFile) resolve_import_specs(name string) []ImportSpec {\n\timports := p.get_imports()\n\tif imports.len == 0 {\n\t\treturn []\n\t}\n\tmut result := []ImportSpec{cap: 2}\n\tfor imp in imports {\n\t\tif imp.import_name() == name {\n\t\t\tresult << imp\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (p &PsiFile) process_declarations(mut processor PsiScopeProcessor) bool {\n\tchildren := p.root.children()\n\tfor child in children {\n\t\t// if child is PsiNamedElement {\n\t\t// \tif !processor.execute(child as PsiElement) {\n\t\t// \t\treturn false\n\t\t// \t}\n\t\t// }\n\t\tif child is ConstantDeclaration {\n\t\t\tfor constant in child.constants() {\n\t\t\t\tif constant is PsiNamedElement {\n\t\t\t\t\tif !processor.execute(constant as PsiElement) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (p &PsiFile) resolve_selective_import_symbol(name string) ?PsiElement {\n\timports := p.get_imports()\n\n\tfor spec in imports {\n\t\tlist := spec.selective_list() or { continue }\n\t\tsymbols := list.symbols()\n\n\t\tfor ref in symbols {\n\t\t\tif ref.name() == name {\n\t\t\t\tif found := p.resolve_symbol_in_import_spec(spec, name) {\n\t\t\t\t\treturn found\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (p &PsiFile) resolve_symbol_in_import_spec(spec ImportSpec, name string) ?PsiElement {\n\timport_name := spec.qualified_name()\n\treal_module_fqn := stubs_index.find_real_module_fqn(import_name)\n\n\tif found := p.find_in_module(real_module_fqn, name) {\n\t\treturn found\n\t}\n\n\treturn none\n}\n\nfn (p &PsiFile) find_in_module(module_fqn string, name string) ?PsiElement {\n\telements := stubs_index.get_all_declarations_from_module(module_fqn, false)\n\tfor element in elements {\n\t\tif element is PsiNamedElement {\n\t\t\tif element.name() == name {\n\t\t\t\treturn element as PsiElement\n\t\t\t}\n\t\t}\n\t}\n\n\ttypes := stubs_index.get_all_declarations_from_module(module_fqn, true)\n\tfor type_element in types {\n\t\tif type_element is PsiNamedElement {\n\t\t\tif type_element.name() == name {\n\t\t\t\treturn type_element as PsiElement\n\t\t\t}\n\t\t}\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiNamedElement.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub interface PsiNamedElement {\n\tparent_of_type(typ bindings.NodeType) ?PsiElement\n\tidentifier_text_range() TextRange\n\tidentifier() ?PsiElement\n\tname() string\n\tis_public() bool\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiReference.v",
    "content": "module psi\n\npub interface PsiReference {\n\telement() PsiElement\n\tresolve() ?PsiElement\n\tmulti_resolve() []PsiElement\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiScopeProcessor.v",
    "content": "module psi\n\npub interface PsiScopeProcessor {\nmut:\n\texecute(element PsiElement) bool\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiTreeWalker.v",
    "content": "module psi\n\nstruct PsiTreeWalker {\nmut:\n\tcontaining_file ?&PsiFile\n\ttree_walker     TreeWalker\n}\n\npub fn (mut tw PsiTreeWalker) next() ?PsiElement {\n\tvalue := tw.tree_walker.next()?\n\treturn create_element(value, tw.containing_file)\n}\n\npub fn new_psi_tree_walker(root_node PsiElement) PsiTreeWalker {\n\treturn PsiTreeWalker{\n\t\ttree_walker:     new_tree_walker(root_node.node())\n\t\tcontaining_file: root_node.containing_file()\n\t}\n}\n\n@[inline]\npub fn (mut tw PsiTreeWalker) free() {\n\ttw.tree_walker.free()\n}\n"
  },
  {
    "path": "src/analyzer/psi/PsiTypedElement.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub interface PsiTypedElement {\n\tget_type() types.Type\n}\n"
  },
  {
    "path": "src/analyzer/psi/QualifiedType.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct QualifiedType {\n\tPsiElementImpl\n}\n\nfn (n &QualifiedType) name() string {\n\treturn ''\n}\n\nfn (n &QualifiedType) qualifier() ?PsiElement {\n\treturn n.first_child_or_stub()\n}\n\nfn (n &QualifiedType) reference() ?PsiReference {\n\tref_expr := n.right()\n\treb := ref_expr? as ReferenceExpressionBase\n\tres := new_reference(n.containing_file(), reb, true)\n\treturn res\n}\n\nfn (n &QualifiedType) resolve() ?PsiElement {\n\treturn n.reference()?.resolve()\n}\n\nfn (n &QualifiedType) get_type() types.Type {\n\tright := n.right() or { return types.unknown_type }\n\tif right is ReferenceExpressionBase {\n\t\tresolved := right.resolve() or { return types.unknown_type }\n\t\tif resolved is PsiTypedElement {\n\t\t\treturn resolved.get_type()\n\t\t}\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (n QualifiedType) left() ?PsiElement {\n\treturn n.first_child_or_stub()\n}\n\npub fn (n QualifiedType) right() ?PsiElement {\n\treturn n.last_child_or_stub()\n}\n"
  },
  {
    "path": "src/analyzer/psi/README.md",
    "content": "## Description\n\n`psi` module describes Program Structure Interface (PSI) for V language.\n"
  },
  {
    "path": "src/analyzer/psi/Range.v",
    "content": "module psi\n\npub struct Range {\n\tPsiElementImpl\n}\n\npub fn (n Range) left() ?PsiElement {\n\treturn n.first_child()\n}\n\npub fn (n Range) right() ?PsiElement {\n\treturn n.last_child()\n}\n\npub fn (n Range) inclusive() bool {\n\top := n.operator() or { return false }\n\treturn op.get_text() == '...'\n}\n\npub fn (n Range) operator() ?PsiElement {\n\tleft := n.left()?\n\treturn left.next_sibling()\n}\n"
  },
  {
    "path": "src/analyzer/psi/Receiver.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct Receiver {\n\tPsiElementImpl\n}\n\npub fn (r &Receiver) is_public() bool {\n\treturn true\n}\n\nfn (r &Receiver) identifier_text_range() TextRange {\n\tif stub := r.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := r.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\nfn (r &Receiver) identifier() ?PsiElement {\n\treturn r.find_child_by_type(.identifier)\n}\n\npub fn (r &Receiver) name() string {\n\tif stub := r.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := r.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (r &Receiver) type_element() ?PsiElement {\n\tif stub := r.get_stub() {\n\t\tif receiver_stub := stub.get_child_by_type(.plain_type) {\n\t\t\tpsi := receiver_stub.get_psi()?\n\t\t\tif psi is PlainType {\n\t\t\t\treturn psi\n\t\t\t}\n\t\t}\n\t\treturn none\n\t}\n\n\treturn r.find_child_by_type(.plain_type)\n}\n\npub fn (r &Receiver) get_type() types.Type {\n\treturn infer_type(r)\n}\n\npub fn (r &Receiver) mutability_modifiers() ?&MutabilityModifiers {\n\tmodifiers := r.find_child_by_type_or_stub(.mutability_modifiers)?\n\tif modifiers is MutabilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (r &Receiver) is_mutable() bool {\n\tmods := r.mutability_modifiers() or { return false }\n\treturn mods.is_mutable()\n}\n\nfn (_ &Receiver) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/RecursiveVisitor.v",
    "content": "module psi\n\npub struct RecursiveVisitorBase {\n}\n\nfn (r &RecursiveVisitorBase) visit_element(element PsiElement) {\n\tif !r.visit_element_impl(element) {\n\t\treturn\n\t}\n\tmut child := element.first_child() or { return }\n\tfor {\n\t\tchild.accept(r)\n\t\tchild = child.next_sibling() or { break }\n\t}\n}\n\nfn (_ &RecursiveVisitorBase) visit_element_impl(element PsiElement) bool {\n\treturn true\n}\n"
  },
  {
    "path": "src/analyzer/psi/ReferenceExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct ReferenceExpression {\n\tPsiElementImpl\n}\n\npub fn (r &ReferenceExpression) is_public() bool {\n\treturn true\n}\n\npub fn (r ReferenceExpression) identifier() ?PsiElement {\n\treturn r.first_child()\n}\n\npub fn (r &ReferenceExpression) identifier_text_range() TextRange {\n\tif stub := r.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := r.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (r &ReferenceExpression) name() string {\n\tif stub := r.get_stub() {\n\t\treturn stub.text\n\t}\n\n\tidentifier := r.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (r ReferenceExpression) qualifier() ?PsiElement {\n\tparent := r.parent()?\n\n\tif parent is SelectorExpression {\n\t\tleft := parent.left()?\n\t\tif left.is_equal(r) {\n\t\t\treturn none\n\t\t}\n\n\t\treturn left\n\t}\n\n\treturn none\n}\n\npub fn (r ReferenceExpression) reference() PsiReference {\n\tif parent := r.parent() {\n\t\tif parent is ValueAttribute {\n\t\t\treturn new_attribute_reference(r.containing_file(), r)\n\t\t}\n\t}\n\n\treturn new_reference(r.containing_file(), r, false)\n}\n\npub fn (r ReferenceExpression) resolve() ?PsiElement {\n\treturn r.reference().resolve()\n}\n\npub fn (r ReferenceExpression) get_type() types.Type {\n\treturn infer_type(r)\n}\n"
  },
  {
    "path": "src/analyzer/psi/ReferenceExpressionBase.v",
    "content": "module psi\n\npub interface ReferenceExpressionBase {\n\tget_text() string\n\ttext_range() TextRange\n\tname() string\n\tqualifier() ?PsiElement\n\treference() PsiReference\n\tresolve() ?PsiElement\n}\n"
  },
  {
    "path": "src/analyzer/psi/ReferenceImpl.v",
    "content": "module psi\n\nimport analyzer.psi.types\nimport utils\n\npub struct ReferenceImpl {\n\telement        ReferenceExpressionBase\n\tfile           ?&PsiFile\n\tfor_types      bool\n\tfor_attributes bool\n}\n\npub fn new_reference(file ?&PsiFile, element ReferenceExpressionBase, for_types bool) &ReferenceImpl {\n\treturn &ReferenceImpl{\n\t\telement:   element\n\t\tfile:      file\n\t\tfor_types: for_types\n\t}\n}\n\npub fn new_attribute_reference(file ?&PsiFile, element ReferenceExpressionBase) &ReferenceImpl {\n\treturn &ReferenceImpl{\n\t\telement:        element\n\t\tfile:           file\n\t\tfor_attributes: true\n\t}\n}\n\nfn (r &ReferenceImpl) element() PsiElement {\n\treturn r.element as PsiElement\n}\n\npub fn (r &ReferenceImpl) resolve() ?PsiElement {\n\tfile := r.file or { return none }\n\n\tsub := SubResolver{\n\t\tcontaining_file: file\n\t\telement:         r.element\n\t\tfor_types:       r.for_types\n\t\tfor_attributes:  r.for_attributes\n\t}\n\tmut processor := ResolveProcessor{\n\t\tcontaining_file: file\n\t\tref:             r.element\n\t\tref_name:        r.element.name()\n\t}\n\n\tif from_cache := resolve_cache.get(r.element()) {\n\t\treturn from_cache\n\t}\n\n\tsub.process_resolve_variants(mut processor)\n\tif processor.result.len == 0 {\n\t\treturn none\n\t}\n\n\tresult := processor.result.first()\n\tresolve_cache.put(r.element(), result)\n\treturn result\n}\n\npub fn (r &ReferenceImpl) multi_resolve() []PsiElement {\n\tfile := r.file or { return [] }\n\n\tif res := r.resolve_as_import_spec() {\n\t\treturn res\n\t}\n\n\tsub := SubResolver{\n\t\tcontaining_file: file\n\t\telement:         r.element\n\t\tfor_types:       r.for_types\n\t\tfor_attributes:  r.for_attributes\n\t}\n\tmut processor := ResolveProcessor{\n\t\tcontaining_file: file\n\t\tref:             r.element\n\t\tref_name:        r.element.name()\n\t\tcollect_all:     true\n\t}\n\n\tsub.process_resolve_variants(mut processor)\n\n\treturn processor.result\n}\n\nfn (r &ReferenceImpl) resolve_as_import_spec() ?[]PsiElement {\n\tif r.element is Identifier {\n\t\tparent := r.element.parent()?\n\t\tif parent !is ImportName {\n\t\t\treturn none\n\t\t}\n\t\tspec := parent.parent()?.parent()?\n\t\tif spec is ImportSpec {\n\t\t\tif ident := spec.identifier() {\n\t\t\t\tif ident.is_equal(parent) {\n\t\t\t\t\treturn [spec]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn none\n}\n\npub struct SubResolver {\npub:\n\tcontaining_file ?&PsiFile\n\telement         ReferenceExpressionBase\n\tfor_types       bool\n\tfor_attributes  bool\n}\n\nfn (r &SubResolver) element() PsiElement {\n\treturn r.element as PsiElement\n}\n\npub fn (r &SubResolver) process_resolve_variants(mut processor PsiScopeProcessor) bool {\n\treturn if qualifier := r.element.qualifier() {\n\t\tr.process_qualifier_expression(qualifier, mut processor)\n\t} else {\n\t\tr.process_unqualified_resolve(mut processor)\n\t}\n}\n\npub fn (r &SubResolver) process_qualifier_expression(qualifier PsiElement, mut processor PsiScopeProcessor) bool {\n\tif qualifier is PsiTypedElement {\n\t\ttyp := infer_type(qualifier as PsiElement)\n\t\tif typ !is types.UnknownType {\n\t\t\tif !r.process_type(typ, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tif qualifier is ReferenceExpressionBase {\n\t\tresolved := qualifier.resolve() or { return true }\n\n\t\tif resolved is ImportSpec {\n\t\t\timport_name := resolved.import_name()\n\t\t\tfile := r.containing_file or { return true }\n\t\t\tspecs := file.resolve_import_specs(import_name)\n\n\t\t\tfor _, spec in specs {\n\t\t\t\ttarget_fqn := spec.qualified_name()\n\t\t\t\treal_fqn := stubs_index.find_real_module_fqn(target_fqn)\n\t\t\t\telements := stubs_index.get_all_declarations_from_module(real_fqn, r.for_types)\n\n\t\t\t\tif !r.process_elements(elements, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\t\tif resolved is ModuleClause {\n\t\t\tfile := r.containing_file or { return true }\n\t\t\tmodule_name := stubs_index.get_module_qualified_name(file.path)\n\t\t\tcurrent_module_elements := stubs_index.get_all_declarations_from_module(module_name,\n\t\t\t\tr.for_types)\n\t\t\tfor elem in current_module_elements {\n\t\t\t\tif !processor.execute(elem) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif resolved is StructDeclaration {\n\t\t\tmethods := static_methods_list(resolved.get_type())\n\t\t\tif !r.process_elements(methods, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) process_elements(elements []PsiElement, mut processor PsiScopeProcessor) bool {\n\tfor element in elements {\n\t\tif !processor.execute(element) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\npub fn (r &SubResolver) process_type(typ types.Type, mut processor PsiScopeProcessor) bool {\n\tif typ is types.StructType {\n\t\tif struct_ := r.find_struct(stubs_index, typ.qualified_name()) {\n\t\t\tis_method_ref := if grand := r.element().parent_nth(2) {\n\t\t\t\tgrand is CallExpression\n\t\t\t} else {\n\t\t\t\tfalse\n\t\t\t}\n\n\t\t\t// If it is a call, then most likely it is a method call, but it\n\t\t\t// could be a function call that is stored in a structure field.\n\t\t\tif is_method_ref {\n\t\t\t\tif !r.process_methods(typ, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tif !r.process_elements(struct_.fields(), mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif !r.process_elements(struct_.fields(), mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tif !r.process_methods(typ, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor def in struct_.embedded_definitions() {\n\t\t\t\tif !processor.execute(def) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.InterfaceType {\n\t\tif interface_ := r.find_interface(stubs_index, typ.qualified_name()) {\n\t\t\tif !r.process_methods(typ, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !r.process_elements(interface_.fields(), mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !r.process_elements(interface_.methods(), mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tfor def in interface_.embedded_definitions() {\n\t\t\t\tif !processor.execute(def) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.EnumType {\n\t\tenum_ := r.find_enum(stubs_index, typ.qualified_name()) or { return true }\n\t\tif !r.process_elements(enum_.fields(), mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_methods(typ, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif enum_.is_flag() {\n\t\t\tif !r.process_type(types.flag_enum_type, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.ArrayType {\n\t\tif !r.process_methods(typ, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_type(types.builtin_array_type, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.MapType {\n\t\tif !r.process_methods(typ, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_type(types.builtin_map_type, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.PointerType {\n\t\tif !r.process_type(typ.inner, mut processor) {\n\t\t\treturn false\n\t\t}\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t}\n\n\tif typ is types.OptionType {\n\t\tif !r.process_type(typ.inner, mut processor) {\n\t\t\treturn false\n\t\t}\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t}\n\n\tif typ is types.ResultType {\n\t\tif !r.process_type(typ.inner, mut processor) {\n\t\t\treturn false\n\t\t}\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t}\n\n\tif typ is types.AliasType {\n\t\tif !r.process_methods(typ, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_type(typ.inner, mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif typ is types.GenericInstantiationType {\n\t\tif !r.process_type(typ.inner, mut processor) {\n\t\t\treturn false\n\t\t}\n\t\tif !r.process_any_type(mut processor) {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t}\n\n\tif !r.process_methods(typ, mut processor) {\n\t\treturn false\n\t}\n\n\tif !r.process_any_type(mut processor) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) process_any_type(mut processor PsiScopeProcessor) bool {\n\treturn r.process_methods(types.any_type, mut processor)\n}\n\npub fn (r &SubResolver) process_methods(typ types.Type, mut processor PsiScopeProcessor) bool {\n\treturn r.process_elements(methods_list(typ), mut processor)\n}\n\npub fn (r &SubResolver) process_unqualified_resolve(mut processor PsiScopeProcessor) bool {\n\tif r.for_attributes {\n\t\treturn r.resolve_attribute(mut processor)\n\t}\n\n\tif parent := r.element().parent() {\n\t\tif parent is FieldName {\n\t\t\treturn r.process_type_initializer_field(mut processor)\n\t\t}\n\n\t\tif parent.element_type() == .enum_fetch {\n\t\t\treturn r.process_enum_fetch(parent, mut processor)\n\t\t}\n\t}\n\n\tif !r.process_block(mut processor) {\n\t\treturn false\n\t}\n\tif !r.process_imported_modules(mut processor) {\n\t\treturn false\n\t}\n\tif !r.process_selective_imports(mut processor) {\n\t\treturn false\n\t}\n\tif !r.process_owner_generic_ts(mut processor) {\n\t\treturn false\n\t}\n\tif !r.process_os_module(mut processor) {\n\t\treturn false\n\t}\n\n\tbuiltin_elements := stubs_index.get_all_declarations_from_module('builtin', r.for_types)\n\tfor element in builtin_elements {\n\t\tif !processor.execute(element) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif r.for_types {\n\t\tstubs_elements := stubs_index.get_all_declarations_from_module('stubs', r.for_types)\n\t\tfor element in stubs_elements {\n\t\t\tif !processor.execute(element) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tmodule_name := if file := r.containing_file {\n\t\tstubs_index.get_module_qualified_name(file.path)\n\t} else {\n\t\t''\n\t}\n\n\telement := r.element()\n\tif element is PsiNamedElement {\n\t\tfqn := if module_name.len != 0 {\n\t\t\tmodule_name + '.' + element.name()\n\t\t} else {\n\t\t\telement.name()\n\t\t}\n\n\t\tif !r.for_types {\n\t\t\tif func := r.find_function(stubs_index, fqn) {\n\t\t\t\tif !processor.execute(func) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif constant := r.find_constant(stubs_index, fqn) {\n\t\t\t\tif !processor.execute(constant) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif struct_ := r.find_struct(stubs_index, fqn) {\n\t\t\tif !processor.execute(struct_) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif interface_ := r.find_interface(stubs_index, fqn) {\n\t\t\tif !processor.execute(interface_) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif enum_ := r.find_enum(stubs_index, fqn) {\n\t\t\tif !processor.execute(enum_) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif alias := r.find_type_alias(stubs_index, fqn) {\n\t\t\tif !processor.execute(alias) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\t// global variable cannot have module name\n\t\tif global_variable := r.find_global_variable(stubs_index, element.name()) {\n\t\t\tif !processor.execute(global_variable) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tmod_decls := stubs_index.get_all_declarations_from_module(module_name, r.for_types)\n\tif !r.process_elements(mod_decls, mut processor) {\n\t\treturn false\n\t}\n\tif !r.process_module_clause(mut processor) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) walk_up(element PsiElement, mut processor PsiScopeProcessor) bool {\n\tmut run := element\n\tmut last_parent := element\n\tfor {\n\t\tif mut run is ForStatement {\n\t\t\tvars := run.var_definitions()\n\t\t\tfor v in vars {\n\t\t\t\tif !processor.execute(v) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif mut run is IfExpression {\n\t\t\tif def := run.var_definition() {\n\t\t\t\tif !processor.execute(def) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif mut run is Block {\n\t\t\tif !run.process_declarations(mut processor, last_parent) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif !r.process_parameters(run, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif !r.process_receiver(run, mut processor) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif mut run is SourceFile {\n\t\t\tif !run.process_declarations(mut processor, last_parent) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif mut run is GenericParametersOwner {\n\t\t\tif parameters := run.generic_parameters() {\n\t\t\t\tparams := parameters.parameters()\n\t\t\t\tfor param in params {\n\t\t\t\t\tif !processor.execute(param) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlast_parent = run\n\t\trun = run.parent() or { break }\n\t}\n\treturn true\n}\n\npub fn (_ &SubResolver) process_parameters(b Block, mut processor PsiScopeProcessor) bool {\n\tparent := b.parent() or { return true }\n\n\tif parent is SignatureOwner {\n\t\tsignature := parent.signature() or { return true }\n\n\t\tparams := signature.parameters()\n\t\tfor param in params {\n\t\t\tif !processor.execute(param) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (_ &SubResolver) process_receiver(b Block, mut processor PsiScopeProcessor) bool {\n\tparent := b.parent() or { return true }\n\n\tif parent is FunctionOrMethodDeclaration {\n\t\treceiver := parent.receiver() or { return true }\n\t\tif !processor.execute(receiver) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) process_block(mut processor PsiScopeProcessor) bool {\n\t// if r.containing_file.is_stub_based() {\n\t// \treturn true\n\t// }\n\n\t// mut delegate := ResolveProcessor{\n\t// \t...processor\n\t// }\n\t// if delegate.result.len == 0 {\n\t// \treturn true\n\t// }\n\t//\n\t// for result in delegate.result {\n\t// \tprocessor.result << result\n\t// }\n\n\treturn r.walk_up(r.element as PsiElement, mut processor)\n}\n\npub fn (r &SubResolver) process_module_clause(mut processor PsiScopeProcessor) bool {\n\tfile := r.containing_file or { return true }\n\tmod := file.module_clause() or { return true }\n\treturn processor.execute(mod)\n}\n\npub fn (r &SubResolver) process_imported_modules(mut processor PsiScopeProcessor) bool {\n\tfile := r.containing_file or { return true }\n\tsearch_name := r.element().get_text()\n\timport_spec := file.resolve_import_spec(search_name) or { return true }\n\n\tif !processor.execute(import_spec) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) process_selective_imports(mut processor PsiScopeProcessor) bool {\n\telement := r.element as PsiElement\n\tname := r.element.name()\n\tfile := r.containing_file or { return true }\n\n\tif parent_list := element.parent_of_type(.selective_import_list) {\n\t\tif spec := parent_list.parent_of_type(.import_spec) {\n\t\t\tif spec is ImportSpec {\n\t\t\t\tif found := file.resolve_symbol_in_import_spec(spec, name) {\n\t\t\t\t\treturn processor.execute(found)\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\tif resolved := file.resolve_selective_import_symbol(name) {\n\t\tif !processor.execute(resolved) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\npub fn (r &SubResolver) process_enum_fetch(parent PsiElement, mut processor PsiScopeProcessor) bool {\n\tcontext_type := TypeInferer{}.infer_context_type(parent)\n\treturn r.process_type(context_type, mut processor)\n}\n\npub fn (r &SubResolver) process_type_initializer_field(mut processor PsiScopeProcessor) bool {\n\tif init_expr := r.element().parent_of_type(.type_initializer) {\n\t\tif init_expr is PsiTypedElement {\n\t\t\ttyp :=\n\t\t\t\ttypes.unwrap_generic_instantiation_type(types.unwrap_pointer_type(infer_type(init_expr as PsiElement)))\n\t\t\tif typ is types.StructType {\n\t\t\t\tif !r.process_struct_type_fields(typ, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\tif typ is types.ArrayType {\n\t\t\t\tif !r.process_struct_type_fields(types.array_init_type, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\tif typ is types.ChannelType {\n\t\t\t\tif !r.process_struct_type_fields(types.chan_init_type, mut processor) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif call_expr := r.element().parent_of_type(.call_expression) {\n\t\tif call_expr is CallExpression {\n\t\t\tresolved := call_expr.resolve() or { return true }\n\t\t\tif resolved is SignatureOwner {\n\t\t\t\tsignature := resolved.signature() or { return true }\n\t\t\t\tparameters := signature.parameters()\n\t\t\t\tif parameters.len == 0 {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\tlast_parameter := parameters.last()\n\t\t\t\tparam_type := infer_type(last_parameter)\n\t\t\t\tif param_type is types.StructType {\n\t\t\t\t\tif !r.process_struct_type_fields(param_type, mut processor) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (r &SubResolver) process_struct_type_fields(struct_type types.StructType, mut processor PsiScopeProcessor) bool {\n\tif struct_ := r.find_struct(stubs_index, struct_type.qualified_name()) {\n\t\tfields := struct_.fields()\n\t\tfor field in fields {\n\t\t\tif !processor.execute(field) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\npub fn (r &SubResolver) process_os_module(mut processor PsiScopeProcessor) bool {\n\tfile := r.containing_file or { return true }\n\n\tif !file.is_shell_script() {\n\t\treturn true\n\t}\n\n\t// In shell scripts OS module is imported implicitly, so we need to process it elements.\n\tos_elements := stubs_index.get_all_declarations_from_module('os', r.for_types)\n\treturn r.process_elements(os_elements, mut processor)\n}\n\npub fn (r &SubResolver) process_owner_generic_ts(mut processor PsiScopeProcessor) bool {\n\telement := r.element()\n\tif element.text_length() != 1 {\n\t\t// for now V only support single char generic parameters\n\t\treturn true\n\t}\n\n\tmethod := element.parent_of_type(.function_declaration) or { return true }\n\tif method is FunctionOrMethodDeclaration {\n\t\treceiver := method.receiver() or { return true }\n\n\t\tif receiver.is_parent_of(element) {\n\t\t\treturn true\n\t\t}\n\n\t\treceiver_type := types.unwrap_alias_type(types.unwrap_pointer_type(receiver.get_type()))\n\t\tif receiver_type is types.GenericInstantiationType {\n\t\t\tinner := receiver_type.inner\n\t\t\tinner_name := inner.qualified_name()\n\t\t\telements := stubs_index.get_any_elements_by_name(inner_name)\n\t\t\tif elements.len == 0 {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tfor resolved in elements {\n\t\t\t\tif resolved is GenericParametersOwner {\n\t\t\t\t\tparams := resolved.generic_parameters() or { continue }\n\t\t\t\t\tparameters := params.parameters()\n\t\t\t\t\tfor param in parameters {\n\t\t\t\t\t\tif !processor.execute(param) {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub fn (_ &SubResolver) find_function(stubs_index StubIndex, name string) ?&FunctionOrMethodDeclaration {\n\tfound := stubs_index.get_elements_by_name(.functions, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is FunctionOrMethodDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_struct(stubs_index StubIndex, name string) ?&StructDeclaration {\n\tfound := stubs_index.get_elements_by_name(.structs, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is StructDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_interface(stubs_index StubIndex, name string) ?&InterfaceDeclaration {\n\tfound := stubs_index.get_elements_by_name(.interfaces, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is InterfaceDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_enum(stubs_index StubIndex, name string) ?&EnumDeclaration {\n\tfound := stubs_index.get_elements_by_name(.enums, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is EnumDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_constant(stubs_index StubIndex, name string) ?&ConstantDefinition {\n\tfound := stubs_index.get_elements_by_name(.constants, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is ConstantDefinition {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_type_alias(stubs_index StubIndex, name string) ?&TypeAliasDeclaration {\n\tfound := stubs_index.get_elements_by_name(.type_aliases, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is TypeAliasDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_global_variable(stubs_index StubIndex, name string) ?&GlobalVarDefinition {\n\tfound := stubs_index.get_elements_by_name(.global_variables, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is GlobalVarDefinition {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (_ &SubResolver) find_attribute(stubs_index StubIndex, name string) ?&StructDeclaration {\n\tfound := stubs_index.get_elements_by_name(.attributes, name)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is StructDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (r &SubResolver) resolve_attribute(mut processor PsiScopeProcessor) bool {\n\telement := r.element()\n\tif element is PsiNamedElement {\n\t\tif attr := r.find_attribute(stubs_index, element.name()) {\n\t\t\tif !processor.execute(attr) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\npub struct ResolveProcessor {\n\tcontaining_file &PsiFile\n\tref             ReferenceExpressionBase\n\tref_name        string\nmut:\n\tresult      []PsiElement\n\tcollect_all bool\n}\n\nfn (mut r ResolveProcessor) execute(element PsiElement) bool {\n\tif element.is_equal(r.ref as PsiElement) {\n\t\tr.result << element\n\t\treturn false\n\t}\n\tif element is PsiNamedElement {\n\t\tmut name := element.name()\n\t\tif name.ends_with('Attribute') {\n\t\t\tname = utils.pascal_case_to_snake_case(name.trim_string_right('Attribute'))\n\t\t}\n\t\tif name == r.ref_name {\n\t\t\tr.result << element as PsiElement\n\t\t\tif r.collect_all {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\npub fn find_element(fqn string) ?PsiElement {\n\tfound := stubs_index.get_any_elements_by_name(fqn)\n\tif found.len != 0 {\n\t\treturn found.first()\n\t}\n\treturn none\n}\n\npub fn find_interface(fqn string) ?&InterfaceDeclaration {\n\tfound := stubs_index.get_elements_by_name(.interfaces, fqn)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is InterfaceDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn find_struct(fqn string) ?&StructDeclaration {\n\tfound := stubs_index.get_elements_by_name(.structs, fqn)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is StructDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n\npub fn find_alias(fqn string) ?&TypeAliasDeclaration {\n\tfound := stubs_index.get_elements_by_name(.type_aliases, fqn)\n\tif found.len != 0 {\n\t\tfirst := found.first()\n\t\tif first is TypeAliasDeclaration {\n\t\t\treturn first\n\t\t}\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/ResolveCache.v",
    "content": "@[translated]\nmodule psi\n\nimport sync\nimport loglib\n\n__global resolve_cache = ResolveCache{}\n\npub struct ResolveCache {\nmut:\n\tmutex sync.RwMutex\n\tdata  map[string]PsiElement\n}\n\npub fn (t &ResolveCache) get(element PsiElement) ?PsiElement {\n\tt.mutex.@rlock()\n\tdefer {\n\t\tt.mutex.runlock()\n\t}\n\n\tfingerprint := t.element_fingerprint(element)\n\treturn t.data[fingerprint] or { return none }\n}\n\npub fn (mut t ResolveCache) put(element PsiElement, result PsiElement) PsiElement {\n\tt.mutex.@lock()\n\tdefer {\n\t\tt.mutex.unlock()\n\t}\n\n\tfingerprint := t.element_fingerprint(element)\n\tt.data[fingerprint] = result\n\treturn result\n}\n\npub fn (mut t ResolveCache) clear() {\n\tt.mutex.@lock()\n\tdefer {\n\t\tt.mutex.unlock()\n\t}\n\n\tloglib.with_fields({\n\t\t'cache_size': t.data.len.str()\n\t}).log_one(.info, 'Clearing resolve cache')\n\n\tt.data = map[string]PsiElement{}\n}\n\n@[inline]\nfn (_ &ResolveCache) element_fingerprint(element PsiElement) string {\n\tfile := element.containing_file() or { return '' }\n\trange := element.text_range()\n\treturn '${file.path}:${element.node().type_name}:${range.line}:${range.column}:${range.end_column}:${range.end_line}'\n}\n"
  },
  {
    "path": "src/analyzer/psi/ResultPropagationExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct ResultPropagationExpression {\n\tPsiElementImpl\n}\n\nfn (c &ResultPropagationExpression) get_type() types.Type {\n\treturn infer_type(c)\n}\n\npub fn (c ResultPropagationExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/SelectiveImportList.v",
    "content": "module psi\n\npub struct SelectiveImportList {\n\tPsiElementImpl\n}\n\npub fn (n &SelectiveImportList) symbols() []ReferenceExpression {\n\tchildren := n.find_children_by_type_or_stub(.reference_expression)\n\tmut res := []ReferenceExpression{cap: children.len}\n\tfor child in children {\n\t\tif child is ReferenceExpression {\n\t\t\tres << child\n\t\t}\n\t}\n\treturn res\n}\n\nfn (n &SelectiveImportList) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/SelectorExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct SelectorExpression {\n\tPsiElementImpl\n}\n\nfn (n &SelectorExpression) name() string {\n\treturn ''\n}\n\nfn (n &SelectorExpression) qualifier() ?PsiElement {\n\treturn n.first_child()\n}\n\nfn (n &SelectorExpression) reference() PsiReference {\n\tright := n.right() or { panic('no right element for SelectorExpression') }\n\tif right is FieldName {\n\t\tif child := right.reference_expression() {\n\t\t\treturn new_reference(n.containing_file(), child, false)\n\t\t}\n\t}\n\tif right is ReferenceExpression {\n\t\treturn new_reference(n.containing_file(), right, false)\n\t}\n\tif right is TypeReferenceExpression {\n\t\treturn new_reference(n.containing_file(), right, true)\n\t}\n\n\tif right is Identifier {\n\t\treturn new_reference(n.containing_file(), right, false)\n\t}\n\tident := &Identifier{\n\t\tPsiElementImpl: new_psi_node(n.containing_file(), right.node())\n\t}\n\treturn new_reference(n.containing_file(), ident, false)\n}\n\nfn (n &SelectorExpression) resolve() ?PsiElement {\n\treturn n.reference().resolve()\n}\n\nfn (n &SelectorExpression) get_type() types.Type {\n\tright := n.right() or { return types.unknown_type }\n\tif right is ReferenceExpressionBase {\n\t\tresolved := right.resolve() or { return types.unknown_type }\n\t\tif resolved is PsiTypedElement {\n\t\t\treturn resolved.get_type()\n\t\t}\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (n SelectorExpression) left() ?PsiElement {\n\treturn n.first_child()\n}\n\npub fn (n SelectorExpression) right() ?PsiElement {\n\treturn n.last_child()\n}\n"
  },
  {
    "path": "src/analyzer/psi/Signature.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct Signature {\n\tPsiElementImpl\n}\n\npub fn (s &Signature) get_type() types.Type {\n\treturn infer_type(s)\n}\n\npub fn (n Signature) parameters() []PsiElement {\n\tmut parameters := []PsiElement{}\n\tif list := n.find_child_by_type_or_stub(.parameter_list) {\n\t\tparameters << list.find_children_by_type_or_stub(.parameter_declaration)\n\t}\n\tif list_type := n.find_child_by_type_or_stub(.type_parameter_list) {\n\t\tparameters << list_type.find_children_by_type_or_stub(.type_parameter_declaration)\n\t}\n\treturn parameters\n}\n\npub fn (n Signature) result() ?PsiElement {\n\tlast := n.last_child_or_stub()?\n\tif last is PlainType {\n\t\treturn last\n\t}\n\treturn none\n}\n\nfn (_ &Signature) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/SignatureOwner.v",
    "content": "module psi\n\npub interface SignatureOwner {\n\tsignature() ?&Signature\n}\n"
  },
  {
    "path": "src/analyzer/psi/SliceExpression.v",
    "content": "module psi\n\npub struct SliceExpression {\n\tPsiElementImpl\n}\n\npub fn (c SliceExpression) expression() ?PsiElement {\n\treturn c.first_child()\n}\n\npub fn (c SliceExpression) resolve() ?PsiElement {\n\texpr := if selector_expr := c.find_child_by_type(.selector_expression) {\n\t\tselector_expr as ReferenceExpressionBase\n\t} else if ref_expr := c.find_child_by_type(.reference_expression) {\n\t\tref_expr as ReferenceExpressionBase\n\t} else {\n\t\treturn none\n\t}\n\n\tif expr is ReferenceExpressionBase {\n\t\tresolved := expr.resolve()?\n\t\treturn resolved\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/SourceFile.v",
    "content": "module psi\n\npub struct SourceFile {\n\tPsiElementImpl\n}\n\npub fn (b SourceFile) process_declarations(mut processor PsiScopeProcessor, last_parent PsiElement) bool {\n\tstatements := b.find_children_by_type(.simple_statement)\n\tfor statement in statements {\n\t\tif statement.is_equal(last_parent) {\n\t\t\treturn true\n\t\t}\n\n\t\tfirst_child := statement.first_child() or { continue }\n\n\t\tif first_child is VarDeclaration {\n\t\t\tfor var in first_child.vars() {\n\t\t\t\tif !processor.execute(var) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "src/analyzer/psi/StaticMethodDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct StaticMethodDeclaration {\n\tPsiElementImpl\n}\n\npub fn (f &StaticMethodDeclaration) generic_parameters() ?&GenericParameters {\n\tgeneric_parameters := f.find_child_by_type_or_stub(.generic_parameters)?\n\tif generic_parameters is GenericParameters {\n\t\treturn generic_parameters\n\t}\n\treturn none\n}\n\npub fn (f &StaticMethodDeclaration) is_public() bool {\n\tmodifiers := f.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\nfn (f &StaticMethodDeclaration) get_type() types.Type {\n\tsignature := f.signature() or { return types.unknown_type }\n\treturn signature.get_type()\n}\n\npub fn (f StaticMethodDeclaration) identifier() ?PsiElement {\n\treturn f.find_child_by_type(.identifier)\n}\n\npub fn (f StaticMethodDeclaration) identifier_text_range() TextRange {\n\tif stub := f.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := f.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (f StaticMethodDeclaration) signature() ?&Signature {\n\tsignature := f.find_child_by_type_or_stub(.signature)?\n\tif signature is Signature {\n\t\treturn signature\n\t}\n\treturn none\n}\n\npub fn (f StaticMethodDeclaration) name() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := f.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (f StaticMethodDeclaration) doc_comment() string {\n\tif stub := f.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(f)\n}\n\npub fn (f StaticMethodDeclaration) receiver_type() types.Type {\n\treceiver := f.receiver() or { return types.unknown_type }\n\treturn receiver.get_type()\n}\n\npub fn (f StaticMethodDeclaration) receiver() ?&StaticReceiver {\n\telement := f.find_child_by_type_or_stub(.static_receiver)?\n\tif element is StaticReceiver {\n\t\treturn element\n\t}\n\treturn none\n}\n\npub fn (f StaticMethodDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := f.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (f StaticMethodDeclaration) owner() ?PsiElement {\n\treceiver := f.receiver()?\n\ttyp := receiver.get_type()\n\tunwrapped := types.unwrap_generic_instantiation_type(types.unwrap_pointer_type(typ))\n\tif unwrapped is types.InterfaceType {\n\t\treturn *find_interface(unwrapped.qualified_name())?\n\t}\n\tif unwrapped is types.StructType {\n\t\treturn *find_struct(unwrapped.qualified_name())?\n\t}\n\tif unwrapped is types.AliasType {\n\t\treturn *find_alias(unwrapped.qualified_name())?\n\t}\n\treturn none\n}\n\npub fn (f StaticMethodDeclaration) fingerprint() string {\n\tsignature := f.signature() or { return '' }\n\tcount_params := signature.parameters().len\n\thas_return_type := if _ := signature.result() { true } else { false }\n\treturn '${f.name()}:${count_params}:${has_return_type}'\n}\n\npub fn (_ StaticMethodDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/StaticReceiver.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct StaticReceiver {\n\tPsiElementImpl\n}\n\npub fn (_ &StaticReceiver) is_public() bool {\n\treturn true\n}\n\nfn (r &StaticReceiver) identifier_text_range() TextRange {\n\tif stub := r.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := r.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\nfn (r &StaticReceiver) identifier() ?PsiElement {\n\treturn r.find_child_by_type(.identifier)\n}\n\npub fn (r &StaticReceiver) name() string {\n\tif stub := r.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := r.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (r &StaticReceiver) get_type() types.Type {\n\treturn infer_type(r.first_child())\n}\n\nfn (_ &StaticReceiver) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/StringLiteral.v",
    "content": "module psi\n\npub struct StringLiteral {\n\tPsiElementImpl\n}\n\npub fn (n StringLiteral) content() string {\n\ttext := n.get_text()\n\treturn text[1..text.len - 1]\n}\n"
  },
  {
    "path": "src/analyzer/psi/StructDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct StructDeclaration {\n\tPsiElementImpl\n}\n\npub fn (s &StructDeclaration) generic_parameters() ?&GenericParameters {\n\tgeneric_parameters := s.find_child_by_type_or_stub(.generic_parameters)?\n\tif generic_parameters is GenericParameters {\n\t\treturn generic_parameters\n\t}\n\treturn none\n}\n\npub fn (s &StructDeclaration) is_public() bool {\n\tmodifiers := s.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\npub fn (s &StructDeclaration) module_name() string {\n\tfile := s.containing_file() or { return '' }\n\treturn stubs_index.get_module_qualified_name(file.path)\n}\n\npub fn (s &StructDeclaration) get_type() types.Type {\n\treturn types.new_struct_type(s.name(), s.module_name())\n}\n\npub fn (s &StructDeclaration) attributes() []PsiElement {\n\tattributes := s.find_child_by_type_or_stub(.attributes) or { return [] }\n\tif attributes is Attributes {\n\t\treturn attributes.attributes()\n\t}\n\n\treturn []\n}\n\npub fn (s StructDeclaration) identifier() ?PsiElement {\n\treturn s.find_child_by_type(.identifier)\n}\n\npub fn (s StructDeclaration) identifier_text_range() TextRange {\n\tif stub := s.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := s.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (s StructDeclaration) name() string {\n\tif stub := s.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := s.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (s StructDeclaration) doc_comment() string {\n\tif stub := s.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(s)\n}\n\npub fn (s StructDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := s.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\npub fn (s StructDeclaration) fields() []PsiElement {\n\tmut fields := s.own_fields()\n\n\tembedded_types := s.embedded_definitions()\n\t\t.map(types.unwrap_alias_type(it.get_type()))\n\t\t.filter(it is types.StructType)\n\n\tfor struct_type in embedded_types {\n\t\tstruct_ := find_struct(struct_type.qualified_name()) or { continue }\n\t\tfields << struct_.fields()\n\t}\n\n\treturn fields\n}\n\npub fn (s StructDeclaration) own_fields() []PsiElement {\n\tfield_declarations := s.find_children_by_type_or_stub(.struct_field_declaration)\n\tmut result := []PsiElement{cap: field_declarations.len}\n\tfor field_declaration in field_declarations {\n\t\tif first_child := field_declaration.first_child_or_stub() {\n\t\t\tif first_child.element_type() != .embedded_definition {\n\t\t\t\tresult << field_declaration\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (s StructDeclaration) embedded_definitions() []&EmbeddedDefinition {\n\tfield_declarations := s.find_children_by_type_or_stub(.struct_field_declaration)\n\tmut result := []&EmbeddedDefinition{cap: field_declarations.len}\n\tfor field_declaration in field_declarations {\n\t\tif embedded_definition := field_declaration.find_child_by_type_or_stub(.embedded_definition) {\n\t\t\tif embedded_definition is EmbeddedDefinition {\n\t\t\t\tresult << embedded_definition\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (s &StructDeclaration) is_attribute() bool {\n\tattrs := s.attributes()\n\tif attrs.len == 0 {\n\t\treturn false\n\t}\n\tattr := attrs.first()\n\tif attr is Attribute {\n\t\tkeys := attr.keys()\n\t\treturn 'attribute' in keys\n\t}\n\n\treturn false\n}\n\npub fn (e StructDeclaration) is_heap() bool {\n\tattributes := e.attributes()\n\n\tfor attr in attributes {\n\t\tif attr is Attribute {\n\t\t\tkeys := attr.keys()\n\t\t\treturn 'heap' in keys\n\t\t}\n\t}\n\n\treturn false\n}\n\npub fn (_ StructDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/StructFieldScope.v",
    "content": "module psi\n\npub struct StructFieldScope {\n\tPsiElementImpl\n}\n\npub fn (n StructFieldScope) is_mutable_public() (bool, bool) {\n\ttext := n.get_text()\n\treturn text.contains('mut'), text.contains('pub')\n}\n\nfn (_ &StructFieldScope) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/StubBase.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub type StubId = int\n\nconst non_stubbed_element = StubId(-1)\n\n@[params]\npub struct StubData {\npub:\n\ttext       string\n\tcomment    string\n\treceiver   string\n\tadditional string\n}\n\n@[heap]\npub struct StubBase {\n\tStubData\npub:\n\tname                  string\n\tidentifier_text_range TextRange\n\ttext_range            TextRange\n\tparent_id             StubId\n\tstub_type             StubType\npub mut:\n\tstub_list &StubList = unsafe { nil }\n\tid        StubId\n}\n\npub fn new_stub_base(parent &StubElement, stub_type StubType, name string, identifier_text_range TextRange,\n\ttext_range TextRange, data StubData) &StubBase {\n\tmut stub_list := if parent is StubBase {\n\t\tif !isnil(parent.stub_list) { parent.stub_list } else { &StubList{} }\n\t} else {\n\t\t&StubList{}\n\t}\n\tparent_id := if !isnil(parent) { parent.id() } else { non_stubbed_element }\n\tmut stub := &StubBase{\n\t\tname:                  name\n\t\ttext:                  data.text\n\t\tcomment:               data.comment\n\t\treceiver:              data.receiver\n\t\tadditional:            data.additional\n\t\tidentifier_text_range: identifier_text_range\n\t\ttext_range:            text_range\n\t\tstub_list:             stub_list\n\t\tparent_id:             parent_id\n\t\tstub_type:             stub_type\n\t}\n\tstub_list.add_stub(mut stub, parent)\n\treturn stub\n}\n\npub fn new_root_stub(path string) &StubBase {\n\tmut stub_list := &StubList{\n\t\tpath: path\n\t}\n\tmut stub := &StubBase{\n\t\tname:      '<root>'\n\t\tstub_list: stub_list\n\t\tparent_id: -1\n\t\tstub_type: .root\n\t}\n\tstub_list.add_stub(mut stub, unsafe { nil })\n\treturn stub\n}\n\npub fn (s &StubBase) id() StubId {\n\treturn s.id\n}\n\npub fn (s &StubBase) stub_type() StubType {\n\treturn s.stub_type\n}\n\npub fn (s &StubBase) element_type() bindings.NodeType {\n\treturn match s.stub_type {\n\t\t.root { .unknown }\n\t\t.function_declaration { .function_declaration }\n\t\t.method_declaration { .function_declaration }\n\t\t.static_method_declaration { .static_method_declaration }\n\t\t.static_receiver { .static_receiver }\n\t\t.receiver { .receiver }\n\t\t.signature { .signature }\n\t\t.parameter_list { .parameter_list }\n\t\t.parameter_declaration { .parameter_declaration }\n\t\t.struct_declaration { .struct_declaration }\n\t\t.interface_declaration { .interface_declaration }\n\t\t.interface_method_declaration { .interface_method_definition }\n\t\t.field_declaration { .struct_field_declaration }\n\t\t.constant_declaration { .const_definition }\n\t\t.type_alias_declaration { .type_declaration }\n\t\t.enum_declaration { .enum_declaration }\n\t\t.enum_field_definition { .enum_field_definition }\n\t\t.struct_field_scope { .struct_field_scope }\n\t\t.attributes { .attributes }\n\t\t.attribute { .attribute }\n\t\t.attribute_expression { .attribute_expression }\n\t\t.value_attribute { .value_attribute }\n\t\t// types\n\t\t.plain_type { .plain_type }\n\t\t.type_reference_expression { .type_reference_expression }\n\t\t.qualified_type { .qualified_type }\n\t\t.pointer_type { .pointer_type }\n\t\t.wrong_pointer_type { .wrong_pointer_type }\n\t\t.array_type { .array_type }\n\t\t.fixed_array_type { .fixed_array_type }\n\t\t.function_type { .function_type }\n\t\t.generic_type { .generic_type }\n\t\t.map_type { .map_type }\n\t\t.channel_type { .channel_type }\n\t\t.shared_type { .shared_type }\n\t\t.thread_type { .thread_type }\n\t\t.multi_return_type { .multi_return_type }\n\t\t.option_type { .option_type }\n\t\t.result_type { .result_type }\n\t\t.type_parameters { .type_parameters }\n\t\t//\n\t\t.visibility_modifiers { .visibility_modifiers }\n\t\t.import_list { .import_list }\n\t\t.import_declaration { .import_declaration }\n\t\t.import_spec { .import_spec }\n\t\t.import_path { .import_path }\n\t\t.import_name { .import_name }\n\t\t.import_alias { .import_alias }\n\t\t.selective_import_list { .selective_import_list }\n\t\t.module_clause { .module_clause }\n\t\t.reference_expression { .reference_expression }\n\t\t.generic_parameters { .generic_parameters }\n\t\t.generic_parameter { .generic_parameter }\n\t\t.global_variable { .global_var_definition }\n\t\t.embedded_definition { .embedded_definition }\n\t}\n}\n\npub fn (s StubBase) name() string {\n\treturn s.name\n}\n\npub fn (s StubBase) text() string {\n\treturn s.text\n}\n\npub fn (s StubBase) receiver() string {\n\treturn s.receiver\n}\n\npub fn (s StubBase) text_range() TextRange {\n\treturn s.identifier_text_range\n}\n\nfn (s StubBase) get_psi() ?PsiElement {\n\treturn StubbedElementType{}.create_psi(s)\n}\n\nfn (s &StubBase) parent_of_type(typ StubType) ?StubElement {\n\tmut res := &StubBase{\n\t\t...s\n\t}\n\tfor {\n\t\tparent := res.parent_stub()?\n\n\t\tif parent is StubBase {\n\t\t\tres = unsafe { parent }\n\t\t} else {\n\t\t\treturn none\n\t\t}\n\n\t\tif res.stub_type == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn (s &StubBase) sibling_of_type_backward(typ StubType) ?StubElement {\n\tmut res := &StubBase{\n\t\t...s\n\t}\n\tfor {\n\t\tprev := res.prev_sibling()?\n\n\t\tif prev is StubBase {\n\t\t\tres = unsafe { prev }\n\t\t} else {\n\t\t\treturn none\n\t\t}\n\n\t\tif res.stub_type == typ {\n\t\t\treturn res\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn (s &StubBase) parent_stub() ?&StubElement {\n\tif s.parent_id == -1 {\n\t\treturn none\n\t}\n\n\treturn s.stub_list.get_stub(s.parent_id) or { return none }\n}\n\nfn (s &StubBase) get_child_by_type(typ StubType) ?StubElement {\n\treturn s.stub_list.get_child_by_type(s.id, typ)\n}\n\nfn (s &StubBase) get_children_by_type(typ StubType) []StubElement {\n\treturn s.stub_list.get_children_stubs(s.id).filter(it.stub_type() == typ)\n}\n\nfn (s &StubBase) has_child_of_type(typ StubType) bool {\n\treturn s.stub_list.has_child_of_type(s.id, typ)\n}\n\nfn (s &StubBase) prev_sibling() ?&StubElement {\n\treturn s.stub_list.prev_sibling(s.id)\n}\n\nfn (s &StubBase) next_sibling() ?&StubElement {\n\treturn s.stub_list.next_sibling(s.id)\n}\n\npub fn (s &StubBase) children_stubs() []StubElement {\n\treturn s.stub_list.get_children_stubs(s.id)\n}\n\nfn (s &StubBase) first_child() ?&StubElement {\n\treturn s.stub_list.first_child(s.id)\n}\n\nfn (s &StubBase) last_child() ?&StubElement {\n\treturn s.stub_list.last_child(s.id)\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubBasedPsiElement.v",
    "content": "module psi\n\n// StubIndexKey describes the various types of indexes that are built on `index.StubTree`.\n// These indexes allow us to quickly find the desired definitions by name in all indexed files,\n// including the standard library and third-party libraries outside the project.\npub enum StubIndexKey as u8 {\n\tfunctions\n\tmethods\n\tstatic_methods\n\tstructs\n\tinterfaces\n\tconstants\n\ttype_aliases\n\tenums\n\tattributes\n\tglobal_variables\n\tmethods_fingerprint\n\tfields_fingerprint\n\tinterface_methods_fingerprint\n\tinterface_fields_fingerprint\n\tmodules_fingerprint\n\t// See count_index_keys\n}\n\n// IndexSink describes the index creator interface.\n// The `occurrence()` method is called for every stub in the file.\n// See `StubbedElementType.index_stub()` for an example of calling this method.\n//\n// The `key` parameter is the index type for which the entry is to be created.\n// The `value` parameter is the string that will be used as the value in the index.\n// For example, for the `functions` index, this would be the name of the function.\npub interface IndexSink {\nmut:\n\toccurrence(key StubIndexKey, value string)\n}\n\n// StubBasedPsiElement describes a marker interface for PSI elements,\n// from which `index.StubTree` will be built, on which stub indexes will be built.\n//\n// PSI elements that implement this interface can be created from\n// both ASTs and stubs (`psi.StubBase`).\n// This allows them to be processed uniformly when resolving names and other\n// processing, since there is no difference whether we are processing a real\n// AST tree or a tree of stubs from memory.\npub interface StubBasedPsiElement {\n\tstub() // marker method\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubElement.v",
    "content": "module psi\n\n// StubElement describes the interface of any stub.\npub interface StubElement {\n\tid() StubId\n\tname() string\n\ttext() string\n\treceiver() string\n\tstub_type() StubType\n\ttext_range() TextRange\n\tparent_stub() ?&StubElement\n\tfirst_child() ?&StubElement\n\tchildren_stubs() []StubElement\n\tget_child_by_type(typ StubType) ?StubElement\n\thas_child_of_type(typ StubType) bool\n\tget_children_by_type(typ StubType) []StubElement\n\tprev_sibling() ?&StubElement\n\tparent_of_type(typ StubType) ?StubElement\n\tget_psi() ?PsiElement\n}\n\npub fn (elements []StubElement) get_psi() []PsiElement {\n\tmut result := []PsiElement{cap: elements.len}\n\tfor element in elements {\n\t\tresult << element.get_psi() or { continue }\n\t}\n\treturn result\n}\n\npub fn is_valid_stub(s StubElement) bool {\n\tif s is StubBase {\n\t\treturn !isnil(s) && !isnil(s.stub_list)\n\t}\n\treturn !isnil(s)\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubIndex.v",
    "content": "@[translated]\nmodule psi\n\nimport time\nimport os\nimport loglib\n\n__global stubs_index = StubIndex{}\n\nconst count_index_keys = 15 // StubIndexKey\n\nconst count_stub_index_location_keys = 5 // StubIndexLocationKind\n\n// StubIndexLocationKind describes the type of index.\n// same as `IndexingRootKind`\npub enum StubIndexLocationKind {\n\tstandard_library\n\tmodules\n\tstubs\n\tworkspace\n}\n\npub struct StubIndex {\npub mut:\n\tsinks []StubIndexSink\n\t// module_to_files describes how to map the full name of a module to a list\n\t// of files that this module contains.\n\tmodule_to_files map[string][]StubIndexSink\n\t// file_to_module describes the mapping of a file path to the full name\n\t// of the module that this file belongs to.\n\tfile_to_module map[string]string\n\t// data defines the index data that allows you to get the description of the element\n\t// in 2 accesses to the array elements and one lookup by key.\n\tdata [count_stub_index_location_keys][count_index_keys]map[string]StubResult\n\t// all_elements_by_modules contains all top-level elements in the module.\n\tall_elements_by_modules [count_stub_index_location_keys]map[string][]PsiElement\n\t// types_by_modules contains all top-level types in the module.\n\ttypes_by_modules [count_stub_index_location_keys]map[string][]PsiElement\n}\n\npub fn new_stubs_index(sinks []StubIndexSink) &StubIndex {\n\tmut index := &StubIndex{\n\t\tsinks:                   sinks\n\t\tmodule_to_files:         map[string][]StubIndexSink{}\n\t\tall_elements_by_modules: unsafe { [count_stub_index_location_keys]map[string][]PsiElement{} }\n\t\ttypes_by_modules:        unsafe { [count_stub_index_location_keys]map[string][]PsiElement{} }\n\t}\n\n\tfor i in 0 .. count_stub_index_location_keys {\n\t\tfor j in 0 .. count_index_keys {\n\t\t\tindex.data[i][j] = map[string]StubResult{}\n\t\t}\n\t}\n\n\twatch := time.new_stopwatch(auto_start: true)\n\tfor sink in sinks {\n\t\tindex.update_index_from_sink(sink)\n\t}\n\n\tloglib.with_duration(watch.elapsed()).log_one(.info, 'Build stubs index')\n\treturn index\n}\n\npub fn (mut s StubIndex) sub_indexes_from_sink(sink StubIndexSink) {\n\tunsafe { s.module_to_files[sink.stub_list.module_fqn] << sink }\n\ts.file_to_module[sink.stub_list.path] = sink.stub_list.module_fqn\n}\n\npub fn (mut s StubIndex) update_index_from_sink(sink StubIndexSink) {\n\telement_type := StubbedElementType{}\n\ts.sub_indexes_from_sink(sink)\n\n\tfor index_id, datum in sink.data {\n\t\tkind := sink.kind\n\n\t\tmut mp := s.data[kind][index_id]\n\t\tfor name, ids in datum {\n\t\t\tmut stubs_result := []&StubBase{cap: ids.len}\n\t\t\tmut psi_result := []PsiElement{cap: ids.len}\n\t\t\tmut top_level_elements_psi_result := []PsiElement{cap: ids.len}\n\t\t\tmut top_level_types_elements_psi_result := []PsiElement{cap: ids.len}\n\n\t\t\tfor stub_id in ids {\n\t\t\t\tstub := sink.stub_list.index_map[stub_id] or { continue }\n\t\t\t\tstubs_result << stub\n\t\t\t\telement := element_type.create_psi(stub) or { continue }\n\t\t\t\tpsi_result << element\n\n\t\t\t\tif stub.stub_type in [\n\t\t\t\t\t.function_declaration,\n\t\t\t\t\t.constant_declaration,\n\t\t\t\t\t.global_variable,\n\t\t\t\t] {\n\t\t\t\t\ttop_level_elements_psi_result << element\n\t\t\t\t}\n\n\t\t\t\tif stub.stub_type in [\n\t\t\t\t\t.struct_declaration,\n\t\t\t\t\t.interface_declaration,\n\t\t\t\t\t.enum_declaration,\n\t\t\t\t\t.type_alias_declaration,\n\t\t\t\t] {\n\t\t\t\t\ttop_level_types_elements_psi_result << element\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmut data_by_name := unsafe { mp[name] }\n\t\t\tdata_by_name.stubs << stubs_result\n\t\t\tdata_by_name.psis << psi_result\n\t\t\tmp[name] = data_by_name\n\n\t\t\tmodule_fqn := sink.module_fqn()\n\t\t\t// V treat different '' (different cap) as different keys\n\t\t\tmodule_key := if module_fqn == '' { '' } else { module_fqn }\n\n\t\t\ts.types_by_modules[kind][module_key] << top_level_types_elements_psi_result\n\n\t\t\ts.all_elements_by_modules[kind][module_key] << top_level_elements_psi_result\n\t\t\ts.all_elements_by_modules[kind][module_key] << top_level_types_elements_psi_result\n\t\t}\n\t\ts.data[kind][index_id] = mp.move()\n\t}\n}\n\npub fn (mut s StubIndex) update_stubs_index(changed_sinks []StubIndexSink, all_sinks []StubIndexSink) {\n\tloglib.log_one(.info, 'Updating stubs index...')\n\tloglib.log_one(.info, 'Changed files: ${changed_sinks.len}')\n\n\ts.sinks = all_sinks\n\n\tmut is_workspace_changes := false\n\tfor sink in changed_sinks {\n\t\tif sink.kind == .workspace {\n\t\t\tis_workspace_changes = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !is_workspace_changes {\n\t\treturn\n\t}\n\n\ts.module_to_files = map[string][]StubIndexSink{}\n\ts.file_to_module = map[string]string{}\n\n\t// clear all workspace index\n\ts.data[StubIndexLocationKind.workspace] = [count_index_keys]map[string]StubResult{}\n\tfor i in 0 .. count_index_keys {\n\t\ts.data[StubIndexLocationKind.workspace][i] = map[string]StubResult{}\n\t}\n\n\ts.all_elements_by_modules[StubIndexLocationKind.workspace] = map[string][]PsiElement{}\n\ts.types_by_modules[StubIndexLocationKind.workspace] = map[string][]PsiElement{}\n\n\tfor sink in all_sinks {\n\t\tif sink.kind != .workspace {\n\t\t\t// for non workspace sinks we just update the module_to_files and file_to_module maps\n\t\t\ts.sub_indexes_from_sink(sink)\n\t\t\tcontinue\n\t\t}\n\n\t\ts.update_index_from_sink(sink)\n\t}\n}\n\n// get_all_elements_from returns a list of all PSI elements defined in the given index.\n//\n// Example:\n// ```\n// // gets all the elements defined in the current project\n// stubs_index.get_all_elements_from(.workspace)\n// ```\npub fn (s &StubIndex) get_all_elements_from(kind StubIndexLocationKind) []PsiElement {\n\tdata := s.data[kind]\n\n\tmut all_len := 0\n\t$for field in StubIndexKey.values {\n\t\tres := data[field.value]\n\t\tfor _, stubs in res {\n\t\t\tall_len += stubs.psis.len\n\t\t}\n\t}\n\tmut elements := []PsiElement{cap: all_len}\n\n\t$for key in StubIndexKey.values {\n\t\tres := data[key.value]\n\t\tfor _, stubs in res {\n\t\t\tfor psi in stubs.psis {\n\t\t\t\telements << psi\n\t\t\t}\n\t\t}\n\t}\n\treturn elements\n}\n\n// get_all_elements_from_by_key returns a list of all PSI elements defined in the given index for the given key.\n//\n// Example:\n// ```\n// // gets all the functions defined in the current project\n// stubs_index.get_all_elements_from_by_key(.workspace, .functions)\n// ```\npub fn (s &StubIndex) get_all_elements_from_by_key(from StubIndexLocationKind, key StubIndexKey) []PsiElement {\n\tdata := s.data[from]\n\tmp := data[key]\n\n\tmut elements := []PsiElement{cap: mp.len}\n\tfor _, res in mp {\n\t\telements << res.psis\n\t}\n\treturn elements\n}\n\npub fn (s &StubIndex) get_all_elements_from_file(file string) []PsiElement {\n\tmut elements := []PsiElement{cap: 20}\n\tfor sink in s.sinks {\n\t\tif sink.stub_list.path != file {\n\t\t\tcontinue\n\t\t}\n\n\t\t$for key in StubIndexKey.values {\n\t\t\tif key.value !in [.attributes, .fields_fingerprint, .methods_fingerprint] {\n\t\t\t\telements << s.get_all_elements_from_sink_by_key(key.value, sink)\n\t\t\t}\n\t\t}\n\t}\n\treturn elements\n}\n\n// get_all_declarations_from_module returns a list of all PSI elements defined in the given module.\npub fn (s &StubIndex) get_all_declarations_from_module(module_fqn string, only_types bool) []PsiElement {\n\tif only_types {\n\t\tif elements := s.types_by_modules[StubIndexLocationKind.workspace][module_fqn] {\n\t\t\treturn elements\n\t\t}\n\n\t\t$for value in StubIndexLocationKind.values {\n\t\t\tif value.value != StubIndexLocationKind.workspace {\n\t\t\t\tif elements := s.types_by_modules[value.value][module_fqn] {\n\t\t\t\t\treturn elements\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// first try to get the elements from the workspace, if not found, try to get them from the other locations\n\tif elements := s.all_elements_by_modules[StubIndexLocationKind.workspace][module_fqn] {\n\t\treturn elements\n\t}\n\n\t$for value in StubIndexLocationKind.values {\n\t\tif value.value != StubIndexLocationKind.workspace {\n\t\t\tif elements := s.all_elements_by_modules[value.value][module_fqn] {\n\t\t\t\treturn elements\n\t\t\t}\n\t\t}\n\t}\n\treturn []\n}\n\npub fn (s &StubIndex) get_all_sinks_from_module(module_fqn string) []StubIndexSink {\n\treturn s.module_to_files[module_fqn] or { return []StubIndexSink{} }\n}\n\npub fn (s &StubIndex) get_all_sink_depends_on(module_fqn string) []StubIndexSink {\n\tmut sinks := []StubIndexSink{cap: 10}\n\tfor sink in s.sinks {\n\t\tif sink.kind != .workspace {\n\t\t\tcontinue\n\t\t}\n\t\tfor imported in sink.imported_modules {\n\t\t\tif s.find_real_module_fqn(imported) == module_fqn {\n\t\t\t\tsinks << sink\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn sinks\n}\n\npub fn (s &StubIndex) get_sink_for_file(file string) ?StubIndexSink {\n\tfor sink in s.sinks {\n\t\tif sink.stub_list.path == file {\n\t\t\treturn sink\n\t\t}\n\t}\n\treturn none\n}\n\n// get_elements_by_name returns the definitions of the element with the given name from the given index.\npub fn (s &StubIndex) get_elements_by_name(key StubIndexKey, name string) []PsiElement {\n\tmut elements := []PsiElement{cap: 5}\n\n\t$for value in StubIndexLocationKind.values {\n\t\tdata := s.data[value.value]\n\t\tres := data[key]\n\t\tif found := res[name] {\n\t\t\telements << found.psis\n\t\t}\n\t}\n\treturn elements\n}\n\npub fn (s &StubIndex) get_elements_from_by_name(from StubIndexLocationKind, key StubIndexKey, name string) []PsiElement {\n\tmut elements := []PsiElement{cap: 5}\n\tdata := s.data[from]\n\tres := data[key]\n\tif found := res[name] {\n\t\telements << found.psis\n\t}\n\treturn elements\n}\n\n// get_any_elements_by_name returns the definitions of the element with the given name.\npub fn (s &StubIndex) get_any_elements_by_name(name string) []PsiElement {\n\tmut elements := []PsiElement{cap: 5}\n\n\t$for value in StubIndexLocationKind.values {\n\t\tdata := s.data[value.value]\n\t\t$for key in StubIndexKey.values {\n\t\t\tif key.value !in [.methods, .attributes] {\n\t\t\t\tres := data[key.value]\n\t\t\t\tif found := res[name] {\n\t\t\t\t\telements << found.psis\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn elements\n}\n\n// get_module_qualified_name returns the fully qualified name of the module in which the file is defined.\npub fn (s &StubIndex) get_module_qualified_name(file string) string {\n\treturn s.file_to_module[file] or { '' }\n}\n\n// get_module_root returns the module's root directory.\npub fn (s &StubIndex) get_module_root(module_fqn string) string {\n\tfiles := s.module_to_files[module_fqn] or { return '' }\n\tfirst := files[0] or { return '' }\n\treturn os.dir(first.stub_list.path)\n}\n\npub fn (s &StubIndex) get_modules_by_name(name string) []PsiElement {\n\tmut elements := []PsiElement{cap: 5}\n\n\t$for value in StubIndexLocationKind.values {\n\t\tdata := s.data[value.value]\n\t\tres := data[int(StubIndexKey.modules_fingerprint)]\n\t\tif found := res[name] {\n\t\t\telements << found.psis\n\t\t}\n\t}\n\treturn elements\n}\n\n// get_all_modules returns all known modules.\npub fn get_all_modules() []string {\n\treturn stubs_index.module_to_files.keys()\n}\n\nfn (_ &StubIndex) get_all_elements_from_sink_by_key(key StubIndexKey, sink StubIndexSink) []PsiElement {\n\tdata := sink.data[int(key)] or { return [] }\n\n\telement_type := StubbedElementType{}\n\tmut elements := []PsiElement{cap: data.len}\n\tfor _, stub_ids in data {\n\t\tfor stub_id in stub_ids {\n\t\t\tstub := sink.stub_list.index_map[stub_id] or { continue }\n\t\t\telements << element_type.create_psi(stub) or { continue }\n\t\t}\n\t}\n\n\treturn elements\n}\n\nstruct StubResult {\nmut:\n\tstubs []&StubBase\n\tpsis  []PsiElement\n}\n\npub fn (s &StubIndex) find_real_module_fqn(name string) string {\n\tworkspace_idx := int(StubIndexLocationKind.workspace)\n\tworkspace_modules := s.all_elements_by_modules[workspace_idx]\n\n\tif name in workspace_modules {\n\t\treturn name\n\t}\n\n\tsuffix := '.' + name\n\tfor mod_fqn, _ in workspace_modules {\n\t\tif mod_fqn.ends_with(suffix) {\n\t\t\treturn mod_fqn\n\t\t}\n\t}\n\n\t$for kind in StubIndexLocationKind.values {\n\t\tif kind.value != StubIndexLocationKind.workspace {\n\t\t\tmodules := s.all_elements_by_modules[kind.value]\n\t\t\tif name in modules {\n\t\t\t\treturn name\n\t\t\t}\n\t\t}\n\t}\n\treturn name\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubIndexSink.v",
    "content": "module psi\n\n@[heap]\npub struct StubIndexSink {\npub mut:\n\tstub_id          StubId\n\tstub_list        &StubList = unsafe { nil } // List of stubs in the current file for which the index is being built.\n\timported_modules []string\n\tkind             StubIndexLocationKind\n\tdata             map[int]map[string][]StubId\n}\n\nconst non_fqn_keys = [StubIndexKey.global_variables, .methods_fingerprint, .fields_fingerprint,\n\t.interface_methods_fingerprint, .interface_fields_fingerprint, .methods, .static_methods,\n\t.attributes, .modules_fingerprint]\n\nfn (mut s StubIndexSink) occurrence(key StubIndexKey, value string) {\n\tmodule_fqn := s.module_fqn()\n\tresulting_value := if module_fqn != '' && key !in non_fqn_keys {\n\t\t'${module_fqn}.${value}'\n\t} else {\n\t\tvalue\n\t}\n\n\ts.data[int(key)][resulting_value] << s.stub_id\n}\n\n@[inline]\npub fn (s StubIndexSink) module_fqn() string {\n\tif s.stub_list == unsafe { nil } {\n\t\treturn ''\n\t}\n\treturn s.stub_list.module_fqn\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubList.v",
    "content": "module psi\n\n// StubList describes a way to store all stubs in a specific file.\n// Storing stubs as a table is more efficient than storing them as a tree, and\n// also makes it easier to serialize stubs to a file.\n@[heap]\npub struct StubList {\npub mut:\n\t// module_fqn is the fully qualified name of the module from the root, eg `foo.bar` or `foo.bar.baz`,\n\t// if no module is defined then the empty string.\n\tmodule_fqn string\n\tpath       string // absolute path to the file\n\tindex_map  map[StubId]&StubBase\n\tchild_map  map[StubId][]int\n}\n\nfn (s StubList) root() &StubBase {\n\treturn s.index_map[0] or {\n\t\t// should never happen\n\t\treturn new_root_stub('unknown file')\n\t}\n}\n\nfn (s &StubList) get_stub(id StubId) ?&StubBase {\n\tif id < 0 {\n\t\treturn none\n\t}\n\treturn s.index_map[id] or { none }\n}\n\nfn (mut s StubList) add_stub(mut stub StubBase, parent &StubElement) {\n\tstub_id := s.index_map.len\n\tstub.id = stub_id\n\ts.index_map[stub_id] = stub\n\n\t// add stub to parent's children\n\tparent_id := if parent != unsafe { nil } && parent is StubBase { parent.id } else { -1 }\n\tmut parent_children := s.child_map[parent_id]\n\tparent_children << stub_id\n\ts.child_map[parent_id] = parent_children\n}\n\nfn (s &StubList) first_child(id StubId) ?&StubElement {\n\tstub := s.get_stub(id)?\n\tchildren_ids := s.child_map[stub.id()]\n\tif children_ids.len == 0 {\n\t\treturn none\n\t}\n\n\tchild_id := children_ids.first()\n\treturn s.index_map[child_id] or { return none }\n}\n\nfn (s &StubList) last_child(id StubId) ?&StubElement {\n\tstub := s.get_stub(id)?\n\tchildren_ids := s.child_map[stub.id()]\n\tif children_ids.len == 0 {\n\t\treturn none\n\t}\n\n\tchild_id := children_ids.last()\n\treturn s.index_map[child_id] or { return none }\n}\n\nfn (s &StubList) get_child_by_type(id StubId, typ StubType) ?StubElement {\n\tstub_ids := s.child_map[id]\n\tfor stub_id in stub_ids {\n\t\tstub := s.index_map[stub_id] or { continue }\n\t\tif stub.stub_type == typ {\n\t\t\treturn stub\n\t\t}\n\t}\n\treturn none\n}\n\nfn (s &StubList) has_child_of_type(id StubId, typ StubType) bool {\n\tstub_ids := s.child_map[id]\n\tfor stub_id in stub_ids {\n\t\tstub := s.index_map[stub_id] or { continue }\n\t\tif stub.stub_type == typ {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfn (s &StubList) get_children_stubs(id StubId) []StubElement {\n\tstub_ids := s.child_map[id]\n\tmut stubs := []StubElement{cap: stub_ids.len}\n\tfor stub_id in stub_ids {\n\t\tstubs << s.index_map[stub_id] or { continue }\n\t}\n\treturn stubs\n}\n\nfn (s &StubList) prev_sibling(id StubId) ?&StubElement {\n\tstub := s.get_stub(id)?\n\tparent := stub.parent_stub()?\n\n\tchildren_ids := s.child_map[parent.id()]\n\tindex := children_ids.index(id)\n\tif index == 0 || index == -1 {\n\t\treturn none\n\t}\n\n\tprev_id := children_ids[index - 1]\n\treturn s.index_map[prev_id] or { return none }\n}\n\nfn (s &StubList) next_sibling(id StubId) ?&StubElement {\n\tstub := s.get_stub(id)?\n\tparent := stub.parent_stub()?\n\n\tchildren_ids := s.child_map[parent.id()]\n\tindex := children_ids.index(id)\n\tif index == 0 || index == -1 {\n\t\treturn none\n\t}\n\n\tprev_id := children_ids[index + 1] or { return none }\n\treturn s.index_map[prev_id] or { return none }\n}\n"
  },
  {
    "path": "src/analyzer/psi/StubbedElementTypeImpl.v",
    "content": "module psi\n\nimport utils\nimport tree_sitter_v.bindings\n\npub enum StubType as u8 {\n\troot\n\tfunction_declaration\n\tmethod_declaration\n\tstatic_method_declaration\n\tstatic_receiver\n\treceiver\n\tsignature\n\tparameter_list\n\tparameter_declaration\n\tstruct_declaration\n\tinterface_declaration\n\tinterface_method_declaration\n\tenum_declaration\n\tfield_declaration\n\tstruct_field_scope\n\tenum_field_definition\n\tconstant_declaration\n\ttype_alias_declaration\n\tattributes\n\tattribute\n\tattribute_expression\n\tvalue_attribute\n\t// types\n\tplain_type\n\ttype_reference_expression\n\tqualified_type\n\tpointer_type\n\twrong_pointer_type\n\tarray_type\n\tfixed_array_type\n\tfunction_type\n\tgeneric_type\n\tmap_type\n\tchannel_type\n\tshared_type\n\tthread_type\n\tmulti_return_type\n\toption_type\n\tresult_type\n\ttype_parameters\n\t//\n\tvisibility_modifiers\n\timport_list\n\timport_declaration\n\timport_spec\n\timport_path\n\timport_name\n\timport_alias\n\tselective_import_list\n\tmodule_clause\n\treference_expression\n\tgeneric_parameters\n\tgeneric_parameter\n\tglobal_variable\n\tembedded_definition\n}\n\npub fn node_type_to_stub_type(typ bindings.NodeType) StubType {\n\treturn match typ {\n\t\t.function_declaration { .function_declaration }\n\t\t.receiver { .receiver }\n\t\t.static_method_declaration { .static_method_declaration }\n\t\t.static_receiver { .static_receiver }\n\t\t.signature { .signature }\n\t\t.parameter_list { .parameter_list }\n\t\t.parameter_declaration { .parameter_declaration }\n\t\t.struct_declaration { .struct_declaration }\n\t\t.interface_declaration { .interface_declaration }\n\t\t.interface_method_definition { .interface_method_declaration }\n\t\t.struct_field_declaration { .field_declaration }\n\t\t.const_definition { .constant_declaration }\n\t\t.type_declaration { .type_alias_declaration }\n\t\t.enum_declaration { .enum_declaration }\n\t\t.enum_field_definition { .enum_field_definition }\n\t\t.struct_field_scope { .struct_field_scope }\n\t\t.attributes { .attributes }\n\t\t.attribute { .attribute }\n\t\t.attribute_expression { .attribute_expression }\n\t\t.value_attribute { .value_attribute }\n\t\t// types\n\t\t.plain_type { .plain_type }\n\t\t.type_reference_expression { .type_reference_expression }\n\t\t.qualified_type { .qualified_type }\n\t\t.pointer_type { .pointer_type }\n\t\t.wrong_pointer_type { .wrong_pointer_type }\n\t\t.array_type { .array_type }\n\t\t.fixed_array_type { .fixed_array_type }\n\t\t.function_type { .function_type }\n\t\t.generic_type { .generic_type }\n\t\t.map_type { .map_type }\n\t\t.channel_type { .channel_type }\n\t\t.shared_type { .shared_type }\n\t\t.thread_type { .thread_type }\n\t\t.multi_return_type { .multi_return_type }\n\t\t.option_type { .option_type }\n\t\t.result_type { .result_type }\n\t\t.type_parameters { .type_parameters }\n\t\t// types end\n\t\t.visibility_modifiers { .visibility_modifiers }\n\t\t.import_list { .import_list }\n\t\t.import_declaration { .import_declaration }\n\t\t.import_spec { .import_spec }\n\t\t.import_path { .import_path }\n\t\t.import_name { .import_name }\n\t\t.import_alias { .import_alias }\n\t\t.selective_import_list { .selective_import_list }\n\t\t.module_clause { .module_clause }\n\t\t.reference_expression { .reference_expression }\n\t\t.generic_parameters { .generic_parameters }\n\t\t.generic_parameter { .generic_parameter }\n\t\t.global_var_definition { .global_variable }\n\t\t.embedded_definition { .embedded_definition }\n\t\telse { .root }\n\t}\n}\n\npub struct StubbedElementType {}\n\npub fn (_ &StubbedElementType) index_stub(stub &StubBase, mut sink IndexSink) {\n\tif stub.stub_list.path.ends_with('_test.v') {\n\t\treturn\n\t}\n\n\tif stub.stub_type == .module_clause {\n\t\tsink.occurrence(.modules_fingerprint, stub.name())\n\t\treturn\n\t}\n\n\tif stub.stub_type == .function_declaration {\n\t\tname := stub.name()\n\t\tif name.starts_with('test_') {\n\t\t\treturn\n\t\t}\n\n\t\tsink.occurrence(.functions, name)\n\t}\n\n\tif stub.stub_type == .method_declaration {\n\t\treceiver := stub.receiver()\n\t\tsink.occurrence(.methods, receiver)\n\t\tsink.occurrence(.methods_fingerprint, stub.additional)\n\t}\n\n\tif stub.stub_type == .static_method_declaration {\n\t\treceiver := stub.receiver()\n\t\tsink.occurrence(.static_methods, receiver)\n\t}\n\n\tif stub.stub_type == .struct_declaration {\n\t\tname := stub.name()\n\t\tif name.ends_with('Attribute') {\n\t\t\t// convert DeprecatedAfter to deprecated_after\n\t\t\tclear_name := utils.pascal_case_to_snake_case(name.trim_string_right('Attribute'))\n\t\t\tsink.occurrence(.attributes, clear_name)\n\t\t\treturn\n\t\t}\n\n\t\tsink.occurrence(.structs, name)\n\t}\n\n\tif stub.stub_type == .interface_declaration {\n\t\tsink.occurrence(.interfaces, stub.name())\n\t}\n\n\tif stub.stub_type == .interface_method_declaration {\n\t\tsink.occurrence(.interface_methods_fingerprint, stub.additional)\n\t}\n\n\tif stub.stub_type == .enum_declaration {\n\t\tsink.occurrence(.enums, stub.name())\n\t}\n\n\tif stub.stub_type == .constant_declaration {\n\t\tsink.occurrence(.constants, stub.name())\n\t}\n\n\tif stub.stub_type == .type_alias_declaration {\n\t\tsink.occurrence(.type_aliases, stub.name())\n\t}\n\n\tif stub.stub_type == .global_variable {\n\t\tsink.occurrence(.global_variables, stub.name())\n\t}\n\n\tif stub.stub_type == .field_declaration {\n\t\tif parent := stub.parent_stub() {\n\t\t\tif parent.stub_type() == .struct_declaration {\n\t\t\t\tsink.occurrence(.fields_fingerprint, stub.name)\n\t\t\t} else if parent.stub_type() == .interface_declaration {\n\t\t\t\tsink.occurrence(.interface_fields_fingerprint, stub.name)\n\t\t\t}\n\t\t}\n\t}\n}\n\npub fn (_ &StubbedElementType) create_psi(stub &StubBase) ?PsiElement {\n\tstub_type := stub.stub_type\n\tbase_psi := new_psi_node_from_stub(stub.id, stub.stub_list)\n\n\tif stub_type == .function_declaration || stub_type == .method_declaration {\n\t\treturn FunctionOrMethodDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .static_method_declaration {\n\t\treturn StaticMethodDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .static_receiver {\n\t\treturn StaticReceiver{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .receiver {\n\t\treturn Receiver{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .signature {\n\t\treturn Signature{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .parameter_list {\n\t\treturn ParameterList{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .parameter_declaration {\n\t\treturn ParameterDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .type_reference_expression {\n\t\treturn TypeReferenceExpression{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .struct_declaration {\n\t\treturn StructDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .interface_declaration {\n\t\treturn InterfaceDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .interface_method_declaration {\n\t\treturn InterfaceMethodDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .enum_declaration {\n\t\treturn EnumDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .enum_field_definition {\n\t\treturn EnumFieldDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .field_declaration {\n\t\treturn FieldDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .struct_field_scope {\n\t\treturn StructFieldScope{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .constant_declaration {\n\t\treturn ConstantDefinition{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .type_alias_declaration {\n\t\treturn TypeAliasDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .attributes {\n\t\treturn Attributes{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .attribute {\n\t\treturn Attribute{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .attribute_expression {\n\t\treturn AttributeExpression{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .value_attribute {\n\t\treturn ValueAttribute{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .plain_type {\n\t\treturn PlainType{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .qualified_type {\n\t\treturn QualifiedType{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .visibility_modifiers {\n\t\treturn VisibilityModifiers{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .import_list {\n\t\treturn ImportList{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .import_declaration {\n\t\treturn ImportDeclaration{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .import_spec {\n\t\treturn ImportSpec{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .import_path {\n\t\treturn ImportPath{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .import_alias {\n\t\treturn ImportAlias{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .selective_import_list {\n\t\treturn SelectiveImportList{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .module_clause {\n\t\treturn ModuleClause{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .reference_expression {\n\t\treturn ReferenceExpression{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .generic_parameters {\n\t\treturn GenericParameters{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .generic_parameter {\n\t\treturn GenericParameter{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .global_variable {\n\t\treturn GlobalVarDefinition{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\tif stub_type == .embedded_definition {\n\t\treturn EmbeddedDefinition{\n\t\t\tPsiElementImpl: base_psi\n\t\t}\n\t}\n\treturn base_psi\n}\n\npub fn (_ &StubbedElementType) get_receiver_type(psi PsiNamedElement) string {\n\ttyp := if psi is FunctionOrMethodDeclaration {\n\t\treceiver := psi.receiver() or { return '' }\n\t\treceiver.type_element() or { return '' }\n\t} else if psi is StaticMethodDeclaration {\n\t\treceiver := psi.receiver() or { return '' }\n\t\tPsiElement(receiver.PsiElementImpl)\n\t} else {\n\t\treturn ''\n\t}\n\n\ttext := typ.get_text().trim_string_left('&')\n\n\tif text.contains('[') && !text.contains('map[') && !text.starts_with('[') {\n\t\t// Foo[T] -> Foo\n\t\treturn text.all_before('[')\n\t}\n\n\treturn text\n}\n\npub fn (s &StubbedElementType) create_stub(psi PsiElement, parent_stub &StubBase, module_fqn string) ?&StubBase {\n\tif psi is FunctionOrMethodDeclaration {\n\t\ttext_range := psi.text_range()\n\t\tidentifier_text_range := psi.identifier_text_range()\n\t\tcomment := psi.doc_comment()\n\n\t\tmut receiver_type := s.get_receiver_type(psi)\n\t\tif receiver_type != '' {\n\t\t\tif module_fqn != '' {\n\t\t\t\treceiver_type = module_fqn + '.' + receiver_type\n\t\t\t}\n\t\t}\n\n\t\tis_method := receiver_type != ''\n\t\tstub_type := if is_method {\n\t\t\tStubType.method_declaration\n\t\t} else {\n\t\t\tStubType.function_declaration\n\t\t}\n\n\t\tfingerprint := if is_method {\n\t\t\tpsi.fingerprint()\n\t\t} else {\n\t\t\t''\n\t\t}\n\n\t\treturn new_stub_base(parent_stub, stub_type, psi.name(), identifier_text_range, text_range,\n\t\t\tcomment:    comment\n\t\t\treceiver:   receiver_type\n\t\t\tadditional: fingerprint\n\t\t)\n\t}\n\n\tif psi is StaticMethodDeclaration {\n\t\ttext_range := psi.text_range()\n\t\tidentifier_text_range := psi.identifier_text_range()\n\t\tcomment := psi.doc_comment()\n\n\t\tmut receiver_type := s.get_receiver_type(psi)\n\t\tif receiver_type != '' {\n\t\t\tif module_fqn != '' {\n\t\t\t\treceiver_type = module_fqn + '.' + receiver_type\n\t\t\t}\n\t\t}\n\n\t\treturn new_stub_base(parent_stub, .static_method_declaration, psi.name(),\n\t\t\tidentifier_text_range, text_range,\n\t\t\tcomment:  comment\n\t\t\treceiver: receiver_type\n\t\t)\n\t}\n\n\tif psi is StructDeclaration {\n\t\ttext_range := psi.text_range()\n\t\tidentifier_text_range := psi.identifier_text_range()\n\t\tcomment := psi.doc_comment()\n\t\tname := if psi.is_attribute() {\n\t\t\tpsi.name() + 'Attribute'\n\t\t} else {\n\t\t\tpsi.name()\n\t\t}\n\t\treturn new_stub_base(parent_stub, .struct_declaration, name, identifier_text_range,\n\t\t\ttext_range,\n\t\t\tcomment: comment\n\t\t)\n\t}\n\n\tif psi is InterfaceDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .interface_declaration)\n\t}\n\n\tif psi is InterfaceMethodDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .interface_method_declaration,\n\t\t\tadditional: psi.fingerprint()\n\t\t)\n\t}\n\n\tif psi is StaticReceiver {\n\t\treturn declaration_stub(*psi, parent_stub, .static_receiver, include_text: true)\n\t}\n\n\tif psi is Receiver {\n\t\treturn declaration_stub(*psi, parent_stub, .receiver, include_text: true)\n\t}\n\n\tif psi is Signature {\n\t\treturn text_based_stub(*psi, parent_stub, .signature)\n\t}\n\n\tif psi is ParameterList {\n\t\treturn text_based_stub(*psi, parent_stub, .parameter_list)\n\t}\n\n\tif psi is ParameterDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .parameter_declaration, include_text: true)\n\t}\n\n\tif psi is EnumDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .enum_declaration)\n\t}\n\n\tif psi is EnumFieldDeclaration {\n\t\tif expression := psi.last_child() {\n\t\t\ttext := expression.get_text()\n\t\t\treturn declaration_stub(*psi, parent_stub, .enum_field_definition, additional: text)\n\t\t}\n\t\treturn declaration_stub(*psi, parent_stub, .enum_field_definition)\n\t}\n\n\tif psi is FieldDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .field_declaration)\n\t}\n\n\tif psi is ConstantDefinition {\n\t\tif expression := psi.last_child() {\n\t\t\ttext := expression.get_text()\n\t\t\treturn declaration_stub(*psi, parent_stub, .constant_declaration, additional: text)\n\t\t}\n\t\treturn declaration_stub(*psi, parent_stub, .constant_declaration)\n\t}\n\n\tif psi is TypeAliasDeclaration {\n\t\treturn declaration_stub(*psi, parent_stub, .type_alias_declaration)\n\t}\n\n\tif psi is StructFieldScope {\n\t\treturn text_based_stub(*psi, parent_stub, .struct_field_scope)\n\t}\n\n\tif psi is Attributes {\n\t\ttext_range := psi.text_range()\n\t\treturn new_stub_base(parent_stub, .attributes, '', text_range, text_range)\n\t}\n\n\tif psi is Attribute {\n\t\treturn text_based_stub(*psi, parent_stub, .attribute)\n\t}\n\n\tif psi is AttributeExpression {\n\t\treturn text_based_stub(*psi, parent_stub, .attribute_expression)\n\t}\n\n\tif psi is ValueAttribute {\n\t\treturn text_based_stub(*psi, parent_stub, .value_attribute)\n\t}\n\n\tif psi is VisibilityModifiers {\n\t\treturn text_based_stub(*psi, parent_stub, .visibility_modifiers)\n\t}\n\n\tif psi is ModuleClause {\n\t\treturn declaration_stub(*psi, parent_stub, .module_clause)\n\t}\n\n\tnode_type := psi.node().type_name\n\tif node_is_type(node_type) {\n\t\tstub_type := node_type_to_stub_type(node_type)\n\t\treturn text_based_stub(psi, parent_stub, stub_type)\n\t}\n\n\tif psi is ImportSpec {\n\t\treturn declaration_stub(*psi, parent_stub, .import_spec, include_text: true)\n\t}\n\n\tif node_type in [\n\t\t.import_list,\n\t\t.import_declaration,\n\t\t.import_path,\n\t\t.import_name,\n\t\t.import_alias,\n\t\t.selective_import_list,\n\t] {\n\t\tstub_type := node_type_to_stub_type(node_type)\n\t\treturn text_based_stub(psi, parent_stub, stub_type,\n\t\t\tinclude_text: node_type !in [\n\t\t\t\t.import_list,\n\t\t\t\t.import_declaration,\n\t\t\t\t.selective_import_list,\n\t\t\t]\n\t\t)\n\t}\n\n\tif psi is ReferenceExpression {\n\t\treturn text_based_stub(*psi, parent_stub, .reference_expression)\n\t}\n\n\tif psi is GenericParameters {\n\t\treturn text_based_stub(*psi, parent_stub, .generic_parameters)\n\t}\n\n\tif psi is GenericParameter {\n\t\treturn declaration_stub(*psi, parent_stub, .generic_parameter)\n\t}\n\n\tif psi is GlobalVarDefinition {\n\t\treturn declaration_stub(*psi, parent_stub, .global_variable)\n\t}\n\n\tif psi is EmbeddedDefinition {\n\t\treturn declaration_stub(*psi, parent_stub, .embedded_definition)\n\t}\n\n\treturn none\n}\n\n@[params]\nstruct StubParams {\npub:\n\tinclude_text bool\n\tadditional   string\n}\n\n@[inline]\npub fn declaration_stub(psi PsiNamedElement, parent_stub &StubElement, stub_type StubType, params StubParams) ?&StubBase {\n\ttext_range := (psi as PsiElement).text_range()\n\tidentifier_text_range := psi.identifier_text_range()\n\treturn new_stub_base(parent_stub, stub_type, psi.name(), identifier_text_range, text_range,\n\t\tcomment:    if psi is PsiDocCommentOwner { psi.doc_comment() } else { '' }\n\t\ttext:       if params.include_text { (psi as PsiElement).get_text() } else { '' }\n\t\tadditional: params.additional\n\t)\n}\n\n@[params]\nstruct TestStubParams {\npub:\n\tinclude_text bool = true\n}\n\n@[inline]\npub fn text_based_stub(psi PsiElement, parent_stub &StubElement, stub_type StubType, params TestStubParams) ?&StubBase {\n\ttext_range := psi.text_range()\n\treturn new_stub_base(parent_stub, stub_type, '', text_range, text_range,\n\t\ttext: if params.include_text { psi.get_text() } else { '' }\n\t)\n}\n\n@[inline]\npub fn node_is_type(type_name bindings.NodeType) bool {\n\treturn type_name in [\n\t\t.plain_type,\n\t\t.type_reference_expression,\n\t\t.qualified_type,\n\t\t.pointer_type,\n\t\t.wrong_pointer_type,\n\t\t.array_type,\n\t\t.fixed_array_type,\n\t\t.function_type,\n\t\t.generic_type,\n\t\t.map_type,\n\t\t.channel_type,\n\t\t.shared_type,\n\t\t.thread_type,\n\t\t.multi_return_type,\n\t\t.option_type,\n\t\t.result_type,\n\t\t.type_parameters,\n\t]\n}\n"
  },
  {
    "path": "src/analyzer/psi/TextRange.v",
    "content": "module psi\n\n// TextRange represents a range of text in a file.\npub struct TextRange {\npub:\n\tline       int\n\tcolumn     int\n\tend_line   int\n\tend_column int\n}\n\npub fn (t TextRange) == (other TextRange) bool {\n\treturn t.line == other.line && t.column == other.column && t.end_line == other.end_line\n\t\t&& t.end_column == other.end_column\n}\n"
  },
  {
    "path": "src/analyzer/psi/TreeWalker.v",
    "content": "module psi\n\nimport tree_sitter_v.bindings\n\npub struct TreeWalker {\nmut:\n\talready_visited_children bool\n\tcursor                   bindings.TreeCursor[bindings.NodeType] @[required]\n}\n\npub fn (mut tw TreeWalker) next() ?AstNode {\n\tif !tw.already_visited_children {\n\t\tif tw.cursor.to_first_child() {\n\t\t\ttw.already_visited_children = false\n\t\t} else if tw.cursor.next() {\n\t\t\ttw.already_visited_children = false\n\t\t} else {\n\t\t\tif !tw.cursor.to_parent() {\n\t\t\t\treturn none\n\t\t\t}\n\t\t\ttw.already_visited_children = true\n\t\t\treturn tw.next()\n\t\t}\n\t} else {\n\t\tif tw.cursor.next() {\n\t\t\ttw.already_visited_children = false\n\t\t} else {\n\t\t\tif !tw.cursor.to_parent() {\n\t\t\t\treturn none\n\t\t\t}\n\t\t\treturn tw.next()\n\t\t}\n\t}\n\tnode := tw.cursor.current_node()?\n\treturn node\n}\n\npub fn new_tree_walker(root_node AstNode) TreeWalker {\n\treturn TreeWalker{\n\t\tcursor: root_node.tree_cursor()\n\t}\n}\n\n@[inline]\npub fn (mut tw TreeWalker) to_first_child() bool {\n\treturn tw.cursor.to_first_child()\n}\n\n@[inline]\npub fn (mut tw TreeWalker) to_parent() bool {\n\treturn tw.cursor.to_parent()\n}\n\n@[inline]\npub fn (mut tw TreeWalker) next_sibling() bool {\n\treturn tw.cursor.next()\n}\n\n@[inline]\npub fn (tw &TreeWalker) current_node() ?AstNode {\n\treturn tw.cursor.current_node()\n}\n\n@[inline]\npub fn (mut tw TreeWalker) free() {\n\tunsafe { tw.cursor.raw_cursor.delete() }\n}\n"
  },
  {
    "path": "src/analyzer/psi/TypeAliasDeclaration.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct TypeAliasDeclaration {\n\tPsiElementImpl\n}\n\npub fn (a &TypeAliasDeclaration) get_type() types.Type {\n\ttypes_list := a.types()\n\tinner_type := if types_list.len > 0 {\n\t\tconvert_type(types_list[0])\n\t} else {\n\t\ttypes.Type(types.unknown_type)\n\t}\n\treturn types.new_alias_type(a.name(), a.module_name(), inner_type)\n}\n\npub fn (a &TypeAliasDeclaration) generic_parameters() ?&GenericParameters {\n\tgeneric_parameters := a.find_child_by_type_or_stub(.generic_parameters)?\n\tif generic_parameters is GenericParameters {\n\t\treturn generic_parameters\n\t}\n\treturn none\n}\n\npub fn (a &TypeAliasDeclaration) is_public() bool {\n\tmodifiers := a.visibility_modifiers() or { return false }\n\treturn modifiers.is_public()\n}\n\npub fn (a &TypeAliasDeclaration) module_name() string {\n\tfile := a.containing_file() or { return '' }\n\treturn stubs_index.get_module_qualified_name(file.path)\n}\n\npub fn (a TypeAliasDeclaration) doc_comment() string {\n\tif stub := a.get_stub() {\n\t\treturn stub.comment\n\t}\n\treturn extract_doc_comment(a)\n}\n\npub fn (a &TypeAliasDeclaration) types() []PlainType {\n\tinner_types := a.find_children_by_type_or_stub(.plain_type)\n\tmut result := []PlainType{cap: inner_types.len}\n\tfor type_ in inner_types {\n\t\tif type_ is PlainType {\n\t\t\tresult << type_\n\t\t}\n\t}\n\treturn result\n}\n\npub fn (a TypeAliasDeclaration) identifier() ?PsiElement {\n\treturn a.find_child_by_type(.identifier)\n}\n\npub fn (a &TypeAliasDeclaration) identifier_text_range() TextRange {\n\tif stub := a.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := a.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (a TypeAliasDeclaration) name() string {\n\tif stub := a.get_stub() {\n\t\treturn stub.name\n\t}\n\n\tidentifier := a.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (a TypeAliasDeclaration) visibility_modifiers() ?&VisibilityModifiers {\n\tmodifiers := a.find_child_by_type_or_stub(.visibility_modifiers)?\n\tif modifiers is VisibilityModifiers {\n\t\treturn modifiers\n\t}\n\treturn none\n}\n\nfn (_ &TypeAliasDeclaration) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/TypeCache.v",
    "content": "@[translated]\nmodule psi\n\nimport analyzer.psi.types\nimport sync\nimport loglib\n\n__global type_cache = TypeCache{}\n\npub struct TypeCache {\nmut:\n\tmutex sync.RwMutex\n\tdata  map[string]types.Type\n}\n\npub fn (t &TypeCache) get(element PsiElement) ?types.Type {\n\tt.mutex.@rlock()\n\tdefer {\n\t\tt.mutex.runlock()\n\t}\n\n\tfingerprint := t.element_fingerprint(element)\n\treturn t.data[fingerprint] or { return none }\n}\n\npub fn (mut t TypeCache) put(element PsiElement, typ types.Type) types.Type {\n\tt.mutex.@lock()\n\tdefer {\n\t\tt.mutex.unlock()\n\t}\n\n\tfingerprint := t.element_fingerprint(element)\n\tt.data[fingerprint] = typ\n\treturn typ\n}\n\npub fn (mut t TypeCache) clear() {\n\tt.mutex.@lock()\n\tdefer {\n\t\tt.mutex.unlock()\n\t}\n\n\tloglib.with_fields({\n\t\t'cache_size': t.data.len.str()\n\t}).log_one(.info, 'Clearing type cache')\n\n\tt.data = map[string]types.Type{}\n}\n\n@[inline]\nfn (_ &TypeCache) element_fingerprint(element PsiElement) string {\n\tfile := element.containing_file() or { return '' }\n\trange := element.text_range()\n\treturn '${file.path}:${element.node().type_name}:${range.line}:${range.column}:${range.end_column}:${range.end_line}'\n}\n"
  },
  {
    "path": "src/analyzer/psi/TypeInferer.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub fn infer_type(elem ?PsiElement) types.Type {\n\treturn TypeInferer{}.infer_type(elem)\n}\n\npub fn convert_type(plain_type ?PsiElement) types.Type {\n\tmut visited := map[string]types.Type{}\n\treturn TypeInferer{}.convert_type(plain_type, mut visited)\n}\n\npub struct TypeInferer {}\n\npub fn (t &TypeInferer) infer_type(elem ?PsiElement) types.Type {\n\telement := elem or { return types.unknown_type }\n\n\tif from_cache := type_cache.get(element) {\n\t\treturn from_cache\n\t}\n\n\ttyp := t.infer_type_impl(elem)\n\ttype_cache.put(element, typ)\n\treturn typ\n}\n\npub fn (t &TypeInferer) infer_type_impl(elem ?PsiElement) types.Type {\n\telement := elem or { return types.unknown_type }\n\n\tmut visited := map[string]types.Type{}\n\n\tmatch element.node().type_name {\n\t\t.in_expression, .is_expression, .select_expression {\n\t\t\treturn types.new_primitive_type('bool')\n\t\t}\n\t\t.inc_expression, .dec_expression {\n\t\t\treturn t.infer_type(element.first_child())\n\t\t}\n\t\t.as_type_cast_expression {\n\t\t\treturn t.infer_type(element.last_child())\n\t\t}\n\t\t.spawn_expression, .go_expression {\n\t\t\treturn types.new_thread_type(t.infer_type(element.last_child()))\n\t\t}\n\t\t.parenthesized_expression {\n\t\t\texpr := element.find_child_by_name('expression') or { return types.unknown_type }\n\t\t\treturn t.infer_type(expr)\n\t\t}\n\t\t.receive_expression {\n\t\t\toperand := element.find_child_by_name('operand') or { return types.unknown_type }\n\t\t\treturn types.unwrap_channel_type(t.infer_type(operand))\n\t\t}\n\t\telse {}\n\t}\n\n\tmatch element {\n\t\tBinaryExpression {\n\t\t\treturn t.infer_binary_expression_type(element)\n\t\t}\n\t\tUnaryExpression {\n\t\t\treturn t.infer_unary_expression_type(element)\n\t\t}\n\t\tOrBlockExpression, ResultPropagationExpression, OptionPropagationExpression {\n\t\t\texpr := element.expression() or { return types.unknown_type }\n\t\t\texpr_type := t.infer_type(expr)\n\t\t\treturn types.unwrap_result_or_option_type(expr_type)\n\t\t}\n\t\tIndexExpression {\n\t\t\treturn t.infer_index_expression_type(element)\n\t\t}\n\t\tSliceExpression {\n\t\t\treturn t.infer_slice_expression_type(element)\n\t\t}\n\t\tRange {\n\t\t\treturn t.infer_range_type(element)\n\t\t}\n\t\tSelectorExpression {\n\t\t\treturn t.infer_selector_expression_type(element)\n\t\t}\n\t\tReferenceExpression {\n\t\t\treturn t.infer_reference_expression_type(element)\n\t\t}\n\t\tTypeInitializer {\n\t\t\treturn t.infer_type_initializer_type(element, mut visited)\n\t\t}\n\t\tUnsafeExpression {\n\t\t\treturn t.infer_unsafe_expression_type(element)\n\t\t}\n\t\tIfExpression {\n\t\t\treturn t.infer_if_expression_type(element)\n\t\t}\n\t\tCompileTimeIfExpression {\n\t\t\treturn t.infer_compile_time_if_expression_type(element)\n\t\t}\n\t\tMatchExpression {\n\t\t\treturn t.infer_match_expression_type(element)\n\t\t}\n\t\tArrayCreation {\n\t\t\treturn t.infer_array_creation_type(element)\n\t\t}\n\t\tMapInitExpression {\n\t\t\treturn t.infer_map_init_expression_type(element)\n\t\t}\n\t\tCallExpression {\n\t\t\treturn t.infer_call_expression_type(element, mut visited)\n\t\t}\n\t\tLiteral {\n\t\t\treturn t.infer_literal_type(element)\n\t\t}\n\t\tSignature {\n\t\t\treturn t.process_signature(element)\n\t\t}\n\t\tVarDefinition {\n\t\t\treturn t.infer_var_definition_type(element)\n\t\t}\n\t\tFieldDeclaration {\n\t\t\treturn t.infer_from_plain_type(element)\n\t\t}\n\t\tReceiver {\n\t\t\treturn t.infer_from_plain_type(element)\n\t\t}\n\t\tParameterDeclaration {\n\t\t\treturn t.infer_parameter_declaration_type(element)\n\t\t}\n\t\tBlock {\n\t\t\treturn t.infer_block_type(element)\n\t\t}\n\t\tFunctionLiteral, FunctionOrMethodDeclaration, StaticMethodDeclaration,\n\t\tInterfaceMethodDeclaration {\n\t\t\tsignature := element.signature() or { return types.unknown_type }\n\t\t\treturn t.process_signature(signature)\n\t\t}\n\t\tEnumDeclaration, EnumFieldDeclaration, ConstantDefinition {\n\t\t\treturn element.get_type()\n\t\t}\n\t\tTypeReferenceExpression {\n\t\t\treturn t.infer_type_reference_type(element, mut visited)\n\t\t}\n\t\tGlobalVarDefinition {\n\t\t\treturn t.infer_global_var_definition_type(element, mut visited)\n\t\t}\n\t\tEmbeddedDefinition {\n\t\t\treturn t.infer_embedded_definition_type(element, mut visited)\n\t\t}\n\t\telse {\n\t\t\treturn types.unknown_type\n\t\t}\n\t}\n}\n\npub fn (t &TypeInferer) infer_binary_expression_type(element BinaryExpression) types.Type {\n\tmatch element.operator() {\n\t\t'&&', '||', '==', '!=', '<', '<=', '>', '>=' {\n\t\t\treturn types.new_primitive_type('bool')\n\t\t}\n\t\t'<<' {\n\t\t\treturn types.new_primitive_type('int')\n\t\t}\n\t\t'>>', '>>>' {\n\t\t\treturn types.new_primitive_type('int')\n\t\t}\n\t\t'+', '-', '|', '^', '&', '*', '/' {\n\t\t\tleft := element.left() or { return types.unknown_type }\n\t\t\tif left.node().type_name != .literal {\n\t\t\t\treturn t.infer_type(left)\n\t\t\t}\n\t\t\tright := element.right() or { return types.unknown_type }\n\t\t\treturn t.infer_type(right)\n\t\t}\n\t\telse {\n\t\t\treturn types.unknown_type\n\t\t}\n\t}\n}\n\npub fn (t &TypeInferer) infer_unary_expression_type(element UnaryExpression) types.Type {\n\toperator := element.operator()\n\tif operator == '!' {\n\t\treturn types.new_primitive_type('bool')\n\t}\n\n\texpression := element.expression() or { return types.unknown_type }\n\texpr_type := t.infer_type(expression)\n\n\treturn match operator {\n\t\t'&' { types.Type(types.new_pointer_type(expr_type)) }\n\t\t'*' { types.unwrap_pointer_type(expr_type) }\n\t\t'<-' { types.unwrap_channel_type(expr_type) }\n\t\telse { expr_type }\n\t}\n}\n\npub fn (t &TypeInferer) infer_index_expression_type(element IndexExpression) types.Type {\n\texpr := element.expression() or { return types.unknown_type }\n\texpr_type := t.infer_type(expr)\n\treturn t.infer_index_type(expr_type)\n}\n\npub fn (t &TypeInferer) infer_slice_expression_type(element SliceExpression) types.Type {\n\texpr := element.expression() or { return types.unknown_type }\n\texpr_type := t.infer_type(expr)\n\tif expr_type is types.FixedArrayType {\n\t\t// [3]int -> []int\n\t\treturn types.new_array_type(expr_type.inner)\n\t}\n\treturn expr_type\n}\n\npub fn (t &TypeInferer) infer_compile_time_if_expression_type(element CompileTimeIfExpression) types.Type {\n\tblock := element.block()\n\tblock_type := t.infer_type(block)\n\tif block_type is types.UnknownType {\n\t\telse_branch := element.else_branch() or { return types.unknown_type }\n\t\treturn t.infer_type(else_branch)\n\t}\n\treturn block_type\n}\n\npub fn (t &TypeInferer) infer_match_expression_type(element MatchExpression) types.Type {\n\tarms := element.arms()\n\tif arms.len == 0 {\n\t\treturn types.unknown_type\n\t}\n\tfirst := arms.first()\n\tblock := first.find_child_by_name('block') or { return types.unknown_type }\n\treturn t.infer_type(block)\n}\n\npub fn (t &TypeInferer) infer_array_creation_type(element ArrayCreation) types.Type {\n\texpressions := element.expressions()\n\tif expressions.len == 0 {\n\t\treturn types.new_array_type(types.unknown_type)\n\t}\n\tfirst_expr := expressions.first()\n\n\tif element.is_fixed {\n\t\treturn types.new_fixed_array_type(t.infer_type(first_expr), expressions.len)\n\t}\n\n\treturn types.new_array_type(t.infer_type(first_expr))\n}\n\npub fn (t &TypeInferer) infer_map_init_expression_type(element MapInitExpression) types.Type {\n\tfile := element.containing_file() or { return types.unknown_type }\n\tmodule_fqn := file.module_fqn()\n\tkey_values := element.key_values()\n\tif key_values.len == 0 {\n\t\treturn types.new_map_type(module_fqn, types.unknown_type, types.unknown_type)\n\t}\n\n\tfirst_key_value := key_values.first()\n\tif first_key_value is MapKeyedElement {\n\t\tkey := first_key_value.key() or { return types.unknown_type }\n\t\tvalue := first_key_value.value() or { return types.unknown_type }\n\t\tkey_type := t.infer_type(key)\n\t\tvalue_type := t.infer_type(value)\n\t\treturn types.new_map_type(module_fqn, key_type, value_type)\n\t}\n\n\treturn types.new_map_type(module_fqn, types.unknown_type, types.unknown_type)\n}\n\npub fn (t &TypeInferer) infer_call_expression_type(element CallExpression, mut visited map[string]types.Type) types.Type {\n\tif grand := element.expression() {\n\t\tif grand is FunctionLiteral {\n\t\t\tsignature := grand.signature() or { return types.unknown_type }\n\t\t\treturn t.convert_type(signature.result(), mut visited)\n\t\t}\n\t}\n\treturn t.infer_call_expr_type(element)\n}\n\npub fn (t &TypeInferer) infer_var_definition_type(element VarDefinition) types.Type {\n\tgrand := element.parent_nth(2) or { return types.unknown_type }\n\tif grand.node().type_name == .range_clause {\n\t\treturn t.process_range_clause(element, grand)\n\t}\n\n\tdecl := element.declaration() or { return types.unknown_type }\n\tif init := decl.initializer_of(element) {\n\t\ttyp := t.infer_type(init)\n\t\tif decl_parent := decl.parent() {\n\t\t\tif decl_parent is IfExpression {\n\t\t\t\treturn types.unwrap_result_or_option_type(typ)\n\t\t\t}\n\t\t}\n\n\t\tif typ is types.MultiReturnType {\n\t\t\tparent := element.parent() or { return types.unknown_type }\n\n\t\t\tmut define_index := 0\n\t\t\tfor index, def in parent.find_children_by_type(.reference_expression) {\n\t\t\t\tif def.is_equal(element) {\n\t\t\t\t\tdefine_index = index\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tinner_types := typ.types\n\t\t\treturn inner_types[define_index] or { return types.unknown_type }\n\t\t}\n\n\t\treturn typ\n\t}\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) infer_parameter_declaration_type(element ParameterDeclaration) types.Type {\n\ttype_ := t.infer_from_plain_type(element)\n\tif _ := element.find_child_by_name('variadic') {\n\t\treturn types.new_array_type(type_)\n\t}\n\treturn type_\n}\n\npub fn (t &TypeInferer) infer_block_type(element Block) types.Type {\n\tlast_expression := element.last_expression() or { return types.unknown_type }\n\treturn t.infer_type(last_expression)\n}\n\npub fn (t &TypeInferer) infer_global_var_definition_type(element GlobalVarDefinition, mut visited map[string]types.Type) types.Type {\n\ttype_element := element.find_child_by_type_or_stub(.plain_type) or { return types.unknown_type }\n\treturn t.convert_type(type_element, mut visited)\n}\n\npub fn (t &TypeInferer) infer_embedded_definition_type(element EmbeddedDefinition, mut visited map[string]types.Type) types.Type {\n\tif qualified_type := element.find_child_by_type_or_stub(.qualified_type) {\n\t\treturn t.convert_type_inner(qualified_type, mut visited)\n\t}\n\tif generic_type := element.find_child_by_type_or_stub(.generic_type) {\n\t\treturn t.convert_type_inner(generic_type, mut visited)\n\t}\n\tif ref_expression := element.find_child_by_type_or_stub(.type_reference_expression) {\n\t\tif ref_expression is TypeReferenceExpression {\n\t\t\treturn t.infer_type_reference_type(ref_expression, mut visited)\n\t\t}\n\t}\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) infer_reference_expression_type(element ReferenceExpression) types.Type {\n\tif resolved := element.resolve() {\n\t\treturn t.infer_type(resolved)\n\t}\n\n\tif element.text_matches('it') {\n\t\tcall := get_it_call(element) or { return types.unknown_type }\n\t\tcaller_type := call.caller_type()\n\t\tif caller_type is types.ArrayType {\n\t\t\treturn caller_type.inner\n\t\t}\n\t\treturn types.unknown_type\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) infer_if_expression_type(element IfExpression) types.Type {\n\tblock := element.block()\n\tblock_type := t.infer_type(block)\n\tif block_type is types.UnknownType {\n\t\telse_branch := element.else_branch() or { return types.unknown_type }\n\t\treturn t.infer_type(else_branch)\n\t}\n\treturn block_type\n}\n\npub fn (t &TypeInferer) infer_unsafe_expression_type(element UnsafeExpression) types.Type {\n\tblock := element.block()\n\treturn t.infer_type(block)\n}\n\npub fn (t &TypeInferer) infer_type_initializer_type(element TypeInitializer, mut visited map[string]types.Type) types.Type {\n\ttype_element := element.find_child_by_type(.plain_type) or { return types.unknown_type }\n\treturn t.convert_type(type_element, mut visited)\n}\n\npub fn (t &TypeInferer) infer_selector_expression_type(element SelectorExpression) types.Type {\n\tresolved := element.resolve() or { return types.unknown_type }\n\ttyp := t.infer_type(resolved)\n\tif types.is_generic(typ) {\n\t\treturn GenericTypeInferer{}.infer_generic_fetch(resolved, element, typ)\n\t}\n\treturn typ\n}\n\npub fn (t &TypeInferer) infer_range_type(element Range) types.Type {\n\tif element.inclusive() {\n\t\tleft := element.left() or { return types.unknown_type }\n\t\treturn t.infer_type(left)\n\t}\n\treturn types.new_array_type(types.new_primitive_type('int'))\n}\n\npub fn (t &TypeInferer) process_signature(signature Signature) types.Type {\n\tparams := signature.parameters()\n\tparam_types := params.map(fn (it PsiElement) types.Type {\n\t\t// TODO: support fn (int, string) without names\n\t\tif it is PsiTypedElement {\n\t\t\treturn it.get_type()\n\t\t}\n\t\treturn types.unknown_type\n\t})\n\tresult := signature.result()\n\tmut visited := map[string]types.Type{}\n\tresult_type := t.convert_type(result, mut visited)\n\tmodule_fqn := if file := signature.containing_file() {\n\t\tfile.module_fqn()\n\t} else {\n\t\t''\n\t}\n\treturn types.new_function_type(module_fqn, param_types, result_type, result == none)\n}\n\npub fn (t &TypeInferer) process_range_clause(element PsiElement, range PsiElement) types.Type {\n\tright := range.find_child_by_name('right') or { return types.unknown_type }\n\tright_type := types.unwrap_alias_type(t.infer_type(right))\n\tvar_definition_list := range.find_child_by_name('left') or { return types.unknown_type }\n\tvar_definitions := var_definition_list.find_children_by_type(.var_definition)\n\n\tif var_definitions.len == 1 {\n\t\tif right_type is types.ArrayType {\n\t\t\treturn right_type.inner\n\t\t}\n\t\tif right_type is types.FixedArrayType {\n\t\t\treturn right_type.inner\n\t\t}\n\t\tif right_type is types.MapType {\n\t\t\treturn right_type.value\n\t\t}\n\t\tif right_type is types.StructType {\n\t\t\tif right_type.name() == 'string' {\n\t\t\t\treturn types.new_primitive_type('u8')\n\t\t\t}\n\n\t\t\treturn t.infer_iterator_struct(right_type)\n\t\t}\n\t}\n\n\tmut define_index := 0\n\tfor index, def in var_definitions {\n\t\tif def.is_equal(element) {\n\t\t\tdefine_index = index\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif define_index == 0 {\n\t\tif right_type is types.MapType {\n\t\t\treturn right_type.key\n\t\t}\n\t\treturn types.new_primitive_type('int')\n\t}\n\n\tif define_index == 1 {\n\t\tif right_type is types.ArrayType {\n\t\t\treturn right_type.inner\n\t\t}\n\t\tif right_type is types.FixedArrayType {\n\t\t\treturn right_type.inner\n\t\t}\n\t\tif right_type is types.MapType {\n\t\t\treturn right_type.value\n\t\t}\n\t\tif right_type is types.StructType {\n\t\t\tif right_type.name() == 'string' {\n\t\t\t\treturn types.new_primitive_type('u8')\n\t\t\t}\n\n\t\t\treturn t.infer_iterator_struct(right_type)\n\t\t}\n\n\t\treturn types.unknown_type\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (_ &TypeInferer) infer_iterator_struct(typ types.Type) types.Type {\n\tmethod := find_method(typ, 'next') or { return types.unknown_type }\n\tif method is FunctionOrMethodDeclaration {\n\t\tsignature := method.signature() or { return types.unknown_type }\n\t\tfunc_type := signature.get_type()\n\t\tif func_type is types.FunctionType {\n\t\t\treturn types.unwrap_result_or_option_type(func_type.result)\n\t\t}\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) infer_call_expr_type(element CallExpression) types.Type {\n\tif element.is_json_decode() {\n\t\treturn types.new_result_type(element.get_json_decode_type(), false)\n\t}\n\n\tif resolved := element.resolve() {\n\t\texpr_type := t.infer_type(resolved)\n\t\tif expr_type is types.FunctionType {\n\t\t\tresult_type := expr_type.result\n\t\t\tif types.is_generic(result_type) {\n\t\t\t\tif resolved is GenericParametersOwner {\n\t\t\t\t\treturn GenericTypeInferer{}.infer_generic_call(element, resolved, result_type)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif resolved is FunctionOrMethodDeclaration {\n\t\t\t\tif !resolved.is_method() {\n\t\t\t\t\treturn result_type\n\t\t\t\t}\n\n\t\t\t\tif typ := t.process_map_array_method_call(resolved, expr_type, element) {\n\t\t\t\t\treturn typ\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result_type\n\t\t}\n\t}\n\n\t// most probably type cast expression: PsiElement(node)\n\t// try to resolve as type\n\texpr := element.ref_expression() or { return types.unknown_type }\n\tref := new_reference(element.containing_file, expr, true)\n\tif resolved := ref.resolve() {\n\t\tif resolved is PsiTypedElement {\n\t\t\treturn resolved.get_type()\n\t\t}\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) process_map_array_method_call(element FunctionOrMethodDeclaration, element_type types.FunctionType,\n\texpr CallExpression) ?types.Type {\n\treceiver_type := types.unwrap_pointer_type(element.receiver_type())\n\n\tif types.is_builtin_array_type(receiver_type) {\n\t\tif typ := t.process_array_method_call(element, element_type, expr) {\n\t\t\treturn typ\n\t\t}\n\t}\n\n\tif types.is_builtin_map_type(receiver_type) {\n\t\tif typ := t.process_map_method_call(element, expr) {\n\t\t\treturn typ\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (_ &TypeInferer) process_array_method_call(element FunctionOrMethodDeclaration, element_type types.FunctionType,\n\texpr CallExpression) ?types.Type {\n\treturn_type := element_type.result\n\n\tif return_type is types.VoidPtrType {\n\t\tcaller_type := expr.caller_type()\n\t\tif caller_type is types.ArrayType {\n\t\t\treturn caller_type.inner\n\t\t}\n\t}\n\n\tif types.is_builtin_array_type(return_type) {\n\t\tif element.name() == 'map' {\n\t\t\targuments := expr.arguments()\n\t\t\tfirst_arg := arguments[0] or { return none }\n\t\t\tfirst_arg_type := infer_type(first_arg)\n\n\t\t\t// map(fn (int) <type> { ... }) -> array<type>\n\t\t\tif first_arg_type is types.FunctionType {\n\t\t\t\treturn *types.new_array_type(first_arg_type.result)\n\t\t\t}\n\n\t\t\t// map(it > 10) -> array<bool>\n\t\t\treturn *types.new_array_type(first_arg_type)\n\t\t}\n\n\t\treturn expr.caller_type()\n\t}\n\n\treturn none\n}\n\npub fn (_ &TypeInferer) process_map_method_call(element FunctionOrMethodDeclaration, expr CallExpression) ?types.Type {\n\tcaller_type := types.unwrap_alias_type(expr.caller_type())\n\n\tif caller_type is types.MapType {\n\t\tmatch element.name() {\n\t\t\t'keys' { return *types.new_array_type(caller_type.key) }\n\t\t\t'values' { return *types.new_array_type(caller_type.value) }\n\t\t\t'clone', 'move' { return caller_type }\n\t\t\telse { return none }\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (_ &TypeInferer) infer_literal_type(element Literal) types.Type {\n\tchild := element.first_child() or { return types.unknown_type }\n\tif child.node().type_name == .interpreted_string_literal\n\t\t|| child.node().type_name == .raw_string_literal {\n\t\treturn types.string_type\n\t}\n\n\tif child.node().type_name == .c_string_literal {\n\t\treturn types.new_pointer_type(types.new_primitive_type('u8'))\n\t}\n\n\tif child.node().type_name == .int_literal {\n\t\treturn types.new_primitive_type('int')\n\t}\n\n\tif child.node().type_name == .float_literal {\n\t\treturn types.new_primitive_type('f64')\n\t}\n\n\tif child.node().type_name == .rune_literal {\n\t\treturn types.new_primitive_type('rune')\n\t}\n\n\tif child.node().type_name == .true_ || child.node().type_name == .false_ {\n\t\treturn types.new_primitive_type('bool')\n\t}\n\n\tif child.node().type_name == .nil_ {\n\t\treturn types.new_primitive_type('voidptr')\n\t}\n\n\tif child.node().type_name == .none_ {\n\t\treturn types.new_primitive_type('none')\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) infer_index_type(typ types.Type) types.Type {\n\tif typ is types.ArrayType {\n\t\treturn typ.inner\n\t}\n\tif typ is types.FixedArrayType {\n\t\treturn typ.inner\n\t}\n\tif typ is types.MapType {\n\t\treturn typ.value\n\t}\n\tif typ is types.StructType {\n\t\tif typ.name == 'string' {\n\t\t\treturn types.new_primitive_type('u8')\n\t\t}\n\n\t\treturn types.unknown_type\n\t}\n\tif typ is types.PointerType {\n\t\treturn typ.inner\n\t}\n\n\treturn types.unknown_type\n}\n\npub fn (t &TypeInferer) convert_type(plain_type ?PsiElement, mut visited map[string]types.Type) types.Type {\n\ttyp := plain_type or { return types.unknown_type }\n\tif typ !is PlainType {\n\t\treturn types.unknown_type\n\t}\n\n\ttype_text := typ.get_text()\n\n\tif type_text in visited {\n\t\treturn visited[type_text]\n\t}\n\n\tmut child := typ.first_child_or_stub() or { return types.unknown_type }\n\tfor child.element_type() == .unknown {\n\t\tchild = child.next_sibling_or_stub() or { return types.unknown_type }\n\t}\n\n\ttype_inner := t.convert_type_inner(child, mut visited)\n\tvisited[type_text] = type_inner\n\treturn type_inner\n}\n\npub fn (t &TypeInferer) convert_type_inner(element PsiElement, mut visited map[string]types.Type) types.Type {\n\tif element.element_type() == .pointer_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_pointer_type(t.convert_type(inner, mut visited))\n\t}\n\n\tif element.element_type() == .array_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_array_type(t.convert_type(inner, mut visited))\n\t}\n\n\tif element.element_type() == .fixed_array_type {\n\t\t// TODO: parse size\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_array_type(t.convert_type(inner, mut visited))\n\t}\n\n\tif element.element_type() == .thread_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_thread_type(t.convert_type(inner, mut visited))\n\t}\n\n\tif element.element_type() == .channel_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_channel_type(t.convert_type(inner, mut visited))\n\t}\n\n\tif element.element_type() == .option_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_option_type(t.convert_type(inner, mut visited), inner == none)\n\t}\n\n\tif element.element_type() == .result_type {\n\t\tinner := element.last_child_or_stub()\n\t\treturn types.new_result_type(t.convert_type(inner, mut visited), inner == none)\n\t}\n\n\tif element.element_type() == .multi_return_type {\n\t\tinner_type_elements := element.find_children_by_type_or_stub(.plain_type)\n\t\tinner_types := inner_type_elements.map(t.convert_type(it, mut visited))\n\t\treturn types.new_multi_return_type(inner_types)\n\t}\n\n\tif element.element_type() == .map_type {\n\t\tfile := element.containing_file() or { return types.unknown_type }\n\t\tmodule_fqn := file.module_fqn()\n\t\ttypes_inner := element.find_children_by_type_or_stub(.plain_type)\n\t\tif types_inner.len != 2 {\n\t\t\treturn types.new_map_type(module_fqn, types.unknown_type, types.unknown_type)\n\t\t}\n\n\t\tkey := types_inner[0]\n\t\tvalue := types_inner[1]\n\t\treturn types.new_map_type(module_fqn, t.convert_type(key, mut visited), t.convert_type(value, mut\n\t\t\tvisited))\n\t}\n\n\tif element.element_type() == .function_type {\n\t\tsignature := element.find_child_by_type_or_stub(.signature) or { return types.unknown_type }\n\t\tif signature is Signature {\n\t\t\treturn t.process_signature(signature)\n\t\t}\n\n\t\treturn types.unknown_type\n\t}\n\n\tif element.element_type() == .generic_type {\n\t\tinner_type := if inner := element.find_child_by_type_or_stub(.type_reference_expression) {\n\t\t\tif inner is TypeReferenceExpression {\n\t\t\t\tt.infer_type_reference_type(inner, mut visited)\n\t\t\t} else {\n\t\t\t\treturn types.unknown_type\n\t\t\t}\n\t\t} else if inner_qualified := element.find_child_by_type_or_stub(.qualified_type) {\n\t\t\tt.convert_type_inner(inner_qualified, mut visited)\n\t\t} else {\n\t\t\treturn types.unknown_type\n\t\t}\n\n\t\ttype_parameters := element.find_child_by_type_or_stub(.type_parameters) or {\n\t\t\treturn inner_type\n\t\t}\n\t\ttype_parameters_list := type_parameters.find_children_by_type_or_stub(.plain_type)\n\n\t\treturn types.new_generic_instantiation_type(inner_type, type_parameters_list.map(t.convert_type(it, mut\n\t\t\tvisited)))\n\t}\n\n\tif element is QualifiedType {\n\t\tif ref := element.right() {\n\t\t\tif ref is TypeReferenceExpression {\n\t\t\t\treturn t.infer_type_reference_type(ref, mut visited)\n\t\t\t}\n\t\t}\n\t}\n\n\tif element is TypeReferenceExpression {\n\t\treturn t.infer_type_reference_type(element, mut visited)\n\t}\n\n\treturn types.unknown_type\n}\n\nfn (t &TypeInferer) infer_type_reference_type(element TypeReferenceExpression, mut visited map[string]types.Type) types.Type {\n\ttext := element.get_text()\n\tif types.is_primitive_type(text) {\n\t\t// fast path\n\t\treturn types.new_primitive_type(text)\n\t}\n\n\tif text == 'string' {\n\t\treturn types.string_type\n\t}\n\n\tif text == 'voidptr' {\n\t\treturn types.voidptr_type\n\t}\n\n\tif text == 'array' {\n\t\treturn types.builtin_array_type\n\t}\n\n\tif text == 'map' {\n\t\treturn types.builtin_map_type\n\t}\n\n\tresolved := element.resolve() or { return types.unknown_type }\n\tif resolved is StructDeclaration {\n\t\treturn resolved.get_type()\n\t}\n\n\tif resolved is InterfaceDeclaration {\n\t\treturn resolved.get_type()\n\t}\n\n\tif resolved is EnumDeclaration {\n\t\treturn resolved.get_type()\n\t}\n\n\tif resolved is TypeAliasDeclaration {\n\t\tname := resolved.name()\n\t\tvisited[name] = types.unknown_type\n\t\ttypes_list := resolved.types()\n\t\tif types_list.len == 0 {\n\t\t\treturn types.unknown_type\n\t\t}\n\t\tfirst := types_list.first()\n\t\talias_type := types.new_alias_type(name, resolved.module_name(), t.convert_type(first, mut\n\t\t\tvisited))\n\t\tvisited[name] = alias_type\n\t\treturn alias_type\n\t}\n\n\tif resolved is GenericParameter {\n\t\treturn types.new_generic_type(element.name())\n\t}\n\n\treturn types.unknown_type\n}\n\nfn (t &TypeInferer) infer_from_plain_type(element PsiElement) types.Type {\n\tplain_typ := element.find_child_by_type_or_stub(.plain_type) or { return types.unknown_type }\n\tmut visited := map[string]types.Type{}\n\treturn t.convert_type(plain_typ, mut visited)\n}\n\npub fn (t &TypeInferer) infer_context_type(elem ?PsiElement) types.Type {\n\telement := elem or { return types.unknown_type }\n\tparent := element.parent() or { return types.unknown_type }\n\n\tif parent.element_type() == .binary_expression {\n\t\tright := parent.last_child_or_stub() or { return types.unknown_type }\n\t\tif right.is_equal(element) {\n\t\t\tleft := parent.first_child_or_stub() or { return types.unknown_type }\n\t\t\treturn t.infer_type(left)\n\t\t}\n\t}\n\n\tif parent.element_type() == .expression_list {\n\t\tgrand := parent.parent() or { return types.unknown_type }\n\t\tif grand.element_type() == .assignment_statement {\n\t\t\t// TODO: support multiple assignments\n\t\t\tright_list := grand.last_child_or_stub() or { return types.unknown_type }\n\t\t\tright := right_list.first_child_or_stub() or { return types.unknown_type }\n\t\t\tif right.is_equal(element) {\n\t\t\t\tleft_list := grand.first_child_or_stub() or { return types.unknown_type }\n\t\t\t\tleft := left_list.first_child_or_stub() or { return types.unknown_type }\n\t\t\t\treturn t.infer_type(left)\n\t\t\t}\n\t\t}\n\t}\n\n\tif parent.element_type() == .match_expression_list {\n\t\tmatch_expr := parent.parent_of_type(.match_expression) or { return types.unknown_type }\n\t\tif match_expr is MatchExpression {\n\t\t\treturn t.infer_type(match_expr.expression())\n\t\t}\n\t}\n\n\tif parent is KeyedElement {\n\t\tfield := parent.field() or { return types.unknown_type }\n\t\tref := field.reference_expression() or { return types.unknown_type }\n\t\tresolved := ref.resolve() or { return types.unknown_type }\n\t\treturn t.infer_from_plain_type(resolved)\n\t}\n\n\tif parent.element_type() == .argument {\n\t\tcall_expression := parent.parent_nth(2) or { return types.unknown_type }\n\t\tif call_expression is CallExpression {\n\t\t\tcalled := call_expression.resolve() or { return types.unknown_type }\n\n\t\t\tif called is FunctionOrMethodDeclaration {\n\t\t\t\tif called.is_method()\n\t\t\t\t\t&& called.receiver_type().qualified_name() == types.flag_enum_type.qualified_name() {\n\t\t\t\t\t// when color.has(.red)\n\t\t\t\t\treturn call_expression.caller_type()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttyp := t.infer_type(called)\n\n\t\t\tif typ is types.FunctionType {\n\t\t\t\tindex := call_expression.parameter_index_on_offset(parent.node().start_byte())\n\t\t\t\tparam_type := typ.params[index] or { return types.unknown_type }\n\t\t\t\treturn param_type\n\t\t\t}\n\t\t}\n\t}\n\n\tif parent.element_type() == .expression_list {\n\t\tgrand := parent.parent() or { return types.unknown_type }\n\t\tif grand.element_type() == .return_statement {\n\t\t\treturn t.enclosing_function_return_type(grand)\n\t\t}\n\t}\n\n\tif parent.element_type() == .simple_statement {\n\t\tif_expr := parent.parent_nth(2) or { return types.unknown_type }\n\t\tif if_expr is IfExpression {\n\t\t\treturn_stmt := if_expr.parent_nth(2) or { return types.unknown_type }\n\t\t\tif return_stmt.element_type() == .return_statement {\n\t\t\t\treturn t.enclosing_function_return_type(return_stmt)\n\t\t\t}\n\t\t}\n\n\t\tmatch_expr := if_expr.parent_nth(2) or { return types.unknown_type }\n\t\tif match_expr is MatchExpression {\n\t\t\treturn_stmt := match_expr.parent_nth(2) or { return types.unknown_type }\n\t\t\tif return_stmt.element_type() == .return_statement {\n\t\t\t\treturn t.enclosing_function_return_type(return_stmt)\n\t\t\t}\n\t\t}\n\t}\n\n\tif parent is FieldDeclaration {\n\t\treturn parent.get_type()\n\t}\n\n\tif parent is ArrayCreation {\n\t\texpressions := parent.expressions()\n\t\tfirst := expressions[0] or { return types.unknown_type }\n\n\t\tif first.element_type() != .enum_fetch {\n\t\t\treturn t.infer_type(first)\n\t\t}\n\n\t\tbin_expr := parent.parent() or { return types.unknown_type }\n\t\tif bin_expr.element_type() in [.binary_expression, .in_expression] {\n\t\t\tleft := bin_expr.first_child_or_stub() or { return types.unknown_type }\n\t\t\tif left.is_parent_of(parent) {\n\t\t\t\treturn types.unknown_type\n\t\t\t}\n\n\t\t\treturn t.infer_type(left)\n\t\t}\n\n\t\treturn types.unknown_type\n\t}\n\n\treturn types.unknown_type\n}\n\nfn (_ &TypeInferer) enclosing_function_return_type(elem PsiElement) types.Type {\n\tfunction := elem.parent_of_any_type(.function_declaration, .function_literal) or {\n\t\treturn types.unknown_type\n\t}\n\tif function is SignatureOwner {\n\t\tsignature := function.signature() or { return types.unknown_type }\n\t\ttyp := signature.get_type()\n\t\tif typ is types.FunctionType {\n\t\t\treturn typ.result\n\t\t}\n\t}\n\treturn types.unknown_type\n}\n"
  },
  {
    "path": "src/analyzer/psi/TypeInitializer.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct TypeInitializer {\n\tPsiElementImpl\n}\n\npub fn (n &TypeInitializer) get_type() types.Type {\n\treturn infer_type(n)\n}\n\npub fn (n &TypeInitializer) element_list() []PsiElement {\n\tbody := n.find_child_by_name('body') or { return [] }\n\telement_list := body.find_child_by_type(.element_list) or { return [] }\n\treturn element_list.named_children()\n}\n"
  },
  {
    "path": "src/analyzer/psi/TypeReferenceExpression.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct TypeReferenceExpression {\n\tPsiElementImpl\n}\n\nfn (_ &TypeReferenceExpression) stub() {}\n\npub fn (_ TypeReferenceExpression) is_public() bool {\n\treturn true\n}\n\npub fn (r TypeReferenceExpression) identifier() ?PsiElement {\n\treturn r.first_child()\n}\n\npub fn (r &TypeReferenceExpression) identifier_text_range() TextRange {\n\tif stub := r.get_stub() {\n\t\treturn stub.identifier_text_range\n\t}\n\n\tidentifier := r.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (r TypeReferenceExpression) name() string {\n\tif stub := r.get_stub() {\n\t\treturn stub.text\n\t}\n\n\tidentifier := r.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (r TypeReferenceExpression) qualifier() ?PsiElement {\n\tparent := r.parent()?\n\n\tif parent is QualifiedType {\n\t\tleft := parent.left()?\n\t\tif left.is_equal(r) {\n\t\t\treturn none\n\t\t}\n\n\t\treturn left\n\t}\n\n\treturn none\n}\n\npub fn (r TypeReferenceExpression) reference() PsiReference {\n\treturn new_reference(r.containing_file, r, true)\n}\n\npub fn (r TypeReferenceExpression) resolve() ?PsiElement {\n\treturn r.reference().resolve()\n}\n\npub fn (r TypeReferenceExpression) get_type() types.Type {\n\telement := r.resolve() or { return types.unknown_type }\n\n\tif element is PsiTypedElement {\n\t\treturn element.get_type()\n\t}\n\n\treturn types.unknown_type\n}\n"
  },
  {
    "path": "src/analyzer/psi/UnaryExpression.v",
    "content": "module psi\n\npub struct UnaryExpression {\n\tPsiElementImpl\n}\n\npub fn (n UnaryExpression) operator() string {\n\toperator_element := n.find_child_by_name('operator') or { return '' }\n\treturn operator_element.get_text()\n}\n\npub fn (n UnaryExpression) expression() ?PsiElement {\n\treturn n.find_child_by_name('operand')\n}\n"
  },
  {
    "path": "src/analyzer/psi/UnsafeExpression.v",
    "content": "module psi\n\npub struct UnsafeExpression {\n\tPsiElementImpl\n}\n\npub fn (n UnsafeExpression) block() ?&Block {\n\tblock := n.find_child_by_type(.block)?\n\tif block is Block {\n\t\treturn block\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/analyzer/psi/ValueAttribute.v",
    "content": "module psi\n\npub struct ValueAttribute {\n\tPsiElementImpl\n}\n\npub fn (n ValueAttribute) value() string {\n\treturn n.get_text()\n}\n\nfn (_ &ValueAttribute) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/VarDeclaration.v",
    "content": "module psi\n\npub struct VarDeclaration {\n\tPsiElementImpl\n}\n\nfn (v VarDeclaration) index_of(def VarDefinition) int {\n\tfirst_child := v.first_child() or { return -1 }\n\tchildren := first_child.children()\n\t\t.filter(it is VarDefinition || it is MutExpression)\n\t\t.map(fn (it PsiElement) PsiElement {\n\t\t\tif it is MutExpression {\n\t\t\t\treturn it.last_child() or { return it }\n\t\t\t}\n\t\t\treturn it\n\t\t})\n\n\tfor i, definition in children {\n\t\tif definition.is_equal(def) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\nfn (v VarDeclaration) initializer_of(def VarDefinition) ?PsiElement {\n\tindex := v.index_of(def)\n\tif index == -1 {\n\t\treturn none\n\t}\n\n\texpressions := v.expressions()\n\tif expressions.len == 1 && expressions.first() is CallExpression {\n\t\treturn expressions.first()\n\t}\n\n\tif index >= expressions.len {\n\t\treturn none\n\t}\n\n\treturn expressions[index]\n}\n\npub fn (v VarDeclaration) vars() []src.analyzer.psi.PsiElement {\n\tfirst_child := v.first_child() or { return [] }\n\treturn first_child\n\t\t.children()\n\t\t.filter(it is VarDefinition || it is MutExpression)\n\t\t.map(fn (it PsiElement) PsiElement {\n\t\t\tif it is MutExpression {\n\t\t\t\treturn it.last_child() or { return it }\n\t\t\t}\n\t\t\treturn it\n\t\t})\n}\n\nfn (v VarDeclaration) expressions() []src.analyzer.psi.PsiElement {\n\tlast_child := v.last_child() or { return [] }\n\treturn last_child.children()\n}\n"
  },
  {
    "path": "src/analyzer/psi/VarDefinition.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub struct VarDefinition {\n\tPsiElementImpl\n}\n\npub fn (_ &VarDefinition) is_public() bool {\n\treturn true\n}\n\npub fn (n &VarDefinition) identifier() ?PsiElement {\n\treturn n.find_child_by_type(.identifier)\n}\n\npub fn (n &VarDefinition) identifier_text_range() TextRange {\n\tidentifier := n.identifier() or { return TextRange{} }\n\treturn identifier.text_range()\n}\n\npub fn (n &VarDefinition) name() string {\n\tidentifier := n.identifier() or { return '' }\n\treturn identifier.get_text()\n}\n\npub fn (n &VarDefinition) declaration() ?&VarDeclaration {\n\tif parent := n.parent_nth(2) {\n\t\tif parent is VarDeclaration {\n\t\t\treturn parent\n\t\t}\n\t}\n\tif parent := n.parent_nth(3) {\n\t\tif parent is VarDeclaration {\n\t\t\treturn parent\n\t\t}\n\t}\n\treturn none\n}\n\npub fn (n &VarDefinition) get_type() types.Type {\n\treturn infer_type(n)\n}\n\npub fn (n &VarDefinition) mutability_modifiers() ?&MutabilityModifiers {\n\tif mut_expr := n.parent() {\n\t\tif mut_expr.node().type_name == .mutable_expression {\n\t\t\tmodifiers := mut_expr.find_child_by_type(.mutability_modifiers)?\n\t\t\tif modifiers is MutabilityModifiers {\n\t\t\t\treturn modifiers\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n\npub fn (n &VarDefinition) is_mutable() bool {\n\tmods := n.mutability_modifiers() or {\n\t\tif first_child := n.first_child() {\n\t\t\tif first_child.text_matches('mut') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif grand := n.parent_nth(4) {\n\t\t\tif grand.element_type() == .for_clause {\n\t\t\t\t// variable inside for loop initializer is mutable by default\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n\treturn mods.is_mutable()\n}\n"
  },
  {
    "path": "src/analyzer/psi/VisibilityModifiers.v",
    "content": "module psi\n\npub struct VisibilityModifiers {\n\tPsiElementImpl\n}\n\npub fn (n VisibilityModifiers) is_public() bool {\n\treturn n.get_text() == 'pub'\n}\n\nfn (n &VisibilityModifiers) stub() {}\n"
  },
  {
    "path": "src/analyzer/psi/doc_comment_extractor.v",
    "content": "module psi\n\nimport strings\n\npub fn extract_doc_comment(el PsiElement) string {\n\tel_start_line := el.node().start_point().row\n\tmut comment := el.prev_sibling() or { return '' }\n\tif comment !is LineComment {\n\t\tcomment = comment.prev_sibling() or { return '' }\n\t}\n\n\tmut comments := []PsiElement{}\n\n\tfor comment is LineComment {\n\t\tcomment_start_line := comment.node().start_point().row\n\n\t\tif comment_start_line + 1 + u32(comments.len) != el_start_line {\n\t\t\tbreak\n\t\t}\n\n\t\tline := comment.prev_sibling() or { break }\n\t\tif line.node().start_point().row == comment_start_line {\n\t\t\tbreak\n\t\t}\n\t\tcomments << comment\n\t\tcomment = line\n\t}\n\n\tmut field_eol_comment := ''\n\tif el is FieldDeclaration {\n\t\tif next := el.next_sibling() {\n\t\t\tif next is LineComment {\n\t\t\t\tcomment_start_line := next.node.start_point().row\n\t\t\t\tif comment_start_line == el_start_line {\n\t\t\t\t\tfield_eol_comment = next.get_text().trim_string_left('//').trim_space()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif comments.len == 0 {\n\t\treturn if field_eol_comment != '' { '... ' + field_eol_comment } else { '' }\n\t}\n\n\tcomments.reverse_in_place()\n\n\tlines := comments.map(it.get_text()\n\t\t.trim_string_left('//')\n\t\t.trim_string_left(' ')\n\t\t.trim_right(' \\t'))\n\n\tmut res := strings.new_builder(lines.len * 40)\n\n\tmut inside_code_block := false\n\n\tfor raw_line in lines {\n\t\tline := raw_line.trim_right(' ')\n\n\t\t// when `--------` line\n\t\tif line.replace('-', '').len == 0 && line.len != 0 {\n\t\t\tres.write_string('\\n\\n')\n\t\t\tcontinue\n\t\t}\n\n\t\tis_end_of_sentence := line.ends_with('.') || line.ends_with('!') || line.ends_with('?')\n\t\t\t|| line.ends_with(':')\n\t\tis_list := line.starts_with('-')\n\t\tis_header := line.starts_with('#')\n\t\tis_table := line.starts_with('|') || line.starts_with('|')\n\t\tis_example := line.starts_with('Example:')\n\t\tis_code_block := line.starts_with('```')\n\n\t\tif is_example || (is_code_block && !inside_code_block) {\n\t\t\tres.write_string('\\n')\n\t\t}\n\n\t\twithout_example_label := line.trim_string_left('Example:').trim_space()\n\t\tif is_example && without_example_label.len != 0 {\n\t\t\tres.write_string('\\nExample:\\n')\n\t\t\tres.write_string('```\\n')\n\t\t\tres.write_string(without_example_label)\n\t\t\tres.write_string('\\n')\n\t\t\tres.write_string('```\\n')\n\t\t} else {\n\t\t\tres.write_string(line)\n\t\t}\n\n\t\tif inside_code_block || is_code_block || is_table {\n\t\t\tres.write_string('\\n')\n\t\t}\n\n\t\tif (is_end_of_sentence || is_list || is_header || is_example) && !inside_code_block {\n\t\t\tres.write_string('\\n')\n\t\t} else if !inside_code_block && !is_code_block {\n\t\t\tres.write_string(' ')\n\t\t}\n\n\t\tif is_code_block {\n\t\t\tinside_code_block = !inside_code_block\n\t\t}\n\t}\n\n\tres_str := res.str() + if field_eol_comment != '' { '\\n\\n... ' + field_eol_comment } else { '' }\n\treturn res_str\n}\n"
  },
  {
    "path": "src/analyzer/psi/element_factory.v",
    "content": "module psi\n\npub fn create_element(node AstNode, containing_file ?&PsiFile) PsiElement {\n\tbase_node := new_psi_node(containing_file, node)\n\n\tif node.type_name == .module_clause {\n\t\treturn &ModuleClause{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .identifier {\n\t\treturn &Identifier{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .plain_type {\n\t\treturn &PlainType{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .selector_expression {\n\t\treturn &SelectorExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .for_statement {\n\t\treturn &ForStatement{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .call_expression {\n\t\treturn &CallExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .argument {\n\t\treturn &Argument{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .index_expression {\n\t\treturn &IndexExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tvar := node_to_var_definition(node, containing_file, base_node)\n\tif !isnil(var) {\n\t\treturn var\n\t}\n\n\tif node.type_name == .reference_expression {\n\t\treturn &ReferenceExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .type_reference_expression {\n\t\treturn &TypeReferenceExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .type_declaration {\n\t\treturn &TypeAliasDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .type_initializer {\n\t\treturn &TypeInitializer{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .field_name {\n\t\treturn &FieldName{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .function_declaration {\n\t\treturn &FunctionOrMethodDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .receiver {\n\t\treturn &Receiver{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .struct_declaration {\n\t\treturn &StructDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .interface_declaration {\n\t\treturn &InterfaceDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .interface_method_definition {\n\t\treturn &InterfaceMethodDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .enum_declaration {\n\t\treturn &EnumDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .struct_field_declaration {\n\t\treturn &FieldDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .struct_field_scope {\n\t\treturn &StructFieldScope{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .enum_field_definition {\n\t\treturn &EnumFieldDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .const_declaration {\n\t\treturn &ConstantDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .const_definition {\n\t\treturn &ConstantDefinition{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .var_declaration {\n\t\treturn &VarDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .block {\n\t\treturn &Block{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .mutable_expression {\n\t\treturn &MutExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .signature {\n\t\treturn &Signature{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .parameter_list {\n\t\treturn &ParameterList{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .parameter_declaration {\n\t\treturn &ParameterDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .literal {\n\t\treturn &Literal{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .line_comment {\n\t\treturn &LineComment{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .block_comment {\n\t\treturn &BlockComment{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .mutability_modifiers {\n\t\treturn &MutabilityModifiers{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .visibility_modifiers {\n\t\treturn &VisibilityModifiers{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .attributes {\n\t\treturn &Attributes{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .attribute {\n\t\treturn &Attribute{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .attribute_expression {\n\t\treturn &AttributeExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .value_attribute {\n\t\treturn &ValueAttribute{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .range {\n\t\treturn &Range{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .interpreted_string_literal {\n\t\treturn &StringLiteral{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .unsafe_expression {\n\t\treturn &UnsafeExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .array_creation {\n\t\treturn &ArrayCreation{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .fixed_array_creation {\n\t\treturn &ArrayCreation{\n\t\t\tPsiElementImpl: base_node\n\t\t\tis_fixed:       true\n\t\t}\n\t}\n\n\tif node.type_name == .map_init_expression {\n\t\treturn &MapInitExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .map_keyed_element {\n\t\treturn &MapKeyedElement{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .function_literal {\n\t\treturn &FunctionLiteral{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .if_expression {\n\t\treturn &IfExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .compile_time_if_expression {\n\t\treturn &CompileTimeIfExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .match_expression {\n\t\treturn &MatchExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_spec {\n\t\treturn &ImportSpec{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .qualified_type {\n\t\treturn &QualifiedType{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_list {\n\t\treturn &ImportList{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_declaration {\n\t\treturn &ImportDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_path {\n\t\treturn &ImportPath{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_name {\n\t\treturn &ImportName{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .import_alias {\n\t\treturn &ImportAlias{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .selective_import_list {\n\t\treturn &SelectiveImportList{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .global_var_definition {\n\t\treturn &GlobalVarDefinition{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .keyed_element {\n\t\treturn &KeyedElement{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .generic_parameters {\n\t\treturn &GenericParameters{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .generic_parameter {\n\t\treturn &GenericParameter{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .slice_expression {\n\t\treturn &SliceExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .embedded_definition {\n\t\treturn &EmbeddedDefinition{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .or_block_expression {\n\t\treturn &OrBlockExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .option_propagation_expression {\n\t\treturn &OptionPropagationExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .result_propagation_expression {\n\t\treturn &ResultPropagationExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .type_parameters {\n\t\treturn &GenericTypeArguments{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .unary_expression {\n\t\treturn &UnaryExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .binary_expression {\n\t\treturn &BinaryExpression{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .source_file {\n\t\treturn &SourceFile{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .static_method_declaration {\n\t\treturn &StaticMethodDeclaration{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\tif node.type_name == .static_receiver {\n\t\treturn &StaticReceiver{\n\t\t\tPsiElementImpl: base_node\n\t\t}\n\t}\n\n\treturn &PsiElementImpl{\n\t\tnode:            node\n\t\tcontaining_file: containing_file\n\t}\n}\n\n@[inline]\npub fn node_to_var_definition(node AstNode, containing_file ?&PsiFile, base_node ?PsiElementImpl) &VarDefinition {\n\tif node.type_name == .var_definition {\n\t\treturn &VarDefinition{\n\t\t\tPsiElementImpl: base_node or { new_psi_node(containing_file, node) }\n\t\t}\n\t}\n\n\tif node.type_name == .reference_expression {\n\t\tparent := node.parent() or { return unsafe { nil } }\n\t\tif parent.type_name != .expression_list && parent.type_name != .mutable_expression {\n\t\t\treturn unsafe { nil }\n\t\t}\n\n\t\tgrand := parent.parent() or { return unsafe { nil } }\n\n\t\tif grand.type_name == .var_declaration {\n\t\t\tvar_list := grand.child_by_field_name('var_list') or { return unsafe { nil } }\n\t\t\tif var_list.is_parent_of(node) {\n\t\t\t\treturn &VarDefinition{\n\t\t\t\t\tPsiElementImpl: base_node or { new_psi_node(containing_file, node) }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif grand_grand := grand.parent() {\n\t\t\tif grand_grand.type_name == .var_declaration && parent.type_name == .mutable_expression {\n\t\t\t\treturn &VarDefinition{\n\t\t\t\t\tPsiElementImpl: base_node or { new_psi_node(containing_file, node) }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn unsafe { nil }\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/ReferencesSearch.v",
    "content": "module search\n\nimport analyzer.psi\nimport analyzer.parser\nimport runtime\nimport math\nimport time\nimport loglib\n\n@[params]\npub struct SearchParams {\npub:\n\t// include_declaration indicates whether to include the declaration\n\t// of the symbol in the search results\n\t// This is useful when we want to find all usages of a symbol for\n\t// refactoring purposes, for example, rename a symbol.\n\t//\n\t// When include_declaration is true, results will include the declaration as `PsiNamedElement`,\n\t// not `Identifier`, so caller should take care of this.\n\t// For example, use `identifier_text_range()` instead of `text_range()` to get the range of the\n\t// identifier.\n\tinclude_declaration bool\n\t// only_in_current_file indicates whether to search only in the current file\n\t// This is set to true when we find references of a symbol for `documentHighlight`\n\t// request.\n\tonly_in_current_file bool\n}\n\npub fn references(element psi.PsiElement, params SearchParams) []psi.PsiElement {\n\tcontaining_file := element.containing_file() or { return [] }\n\treturn ReferencesSearch{\n\t\tparams:          params\n\t\tcontaining_file: containing_file\n\t}.search(element)\n}\n\nstruct ReferencesSearch {\n\tparams          SearchParams\n\tcontaining_file &psi.PsiFile\n}\n\npub fn (r &ReferencesSearch) search(element psi.PsiElement) []psi.PsiElement {\n\tresolved := resolve_identifier(element) or { return [] }\n\tif resolved is psi.VarDefinition {\n\t\t// variables cannot be used outside the scope where they are defined\n\t\tscope := element.parent_of_any_type(.block, .source_file) or { return [] }\n\t\treturn r.search_in_scope(resolved, scope)\n\t}\n\tif resolved is psi.ParameterDeclaration {\n\t\tparent := resolved.parent_of_any_type(.function_literal, .function_declaration) or {\n\t\t\treturn []\n\t\t}\n\t\treturn r.search_in_scope(resolved, parent)\n\t}\n\tif resolved is psi.Receiver {\n\t\tparent := resolved.parent_of_type(.function_declaration) or { return [] }\n\t\treturn r.search_in_scope(resolved, parent)\n\t}\n\tif resolved is psi.ImportName {\n\t\timport_spec := resolved.parent_of_type(.import_spec) or { return [] }\n\t\tif import_spec is psi.ImportSpec {\n\t\t\tfile := element.containing_file() or { return [] }\n\t\t\treturn r.search_in_scope(import_spec, file.root())\n\t\t}\n\t\treturn []\n\t}\n\tif resolved is psi.ModuleClause {\n\t\treturn r.search_module_import(resolved)\n\t}\n\tif resolved is psi.GenericParameter {\n\t\treturn r.search_generic_parameter(resolved)\n\t}\n\tif resolved is psi.FunctionOrMethodDeclaration {\n\t\tif resolved.is_method() {\n\t\t\treturn r.search_method(resolved)\n\t\t}\n\t}\n\tif resolved is psi.PsiNamedElement {\n\t\treturn r.search_named_element(resolved)\n\t}\n\treturn []\n}\n\n// search_method searches references of a method.\n//\n// If the struct of the method implements some interface, we must also look for the use of the\n// interface method, since the method of the struct for which we are looking for references is\n// also implicitly called through it.\n//\n// This is important for renaming, because if we rename a struct method, we must also rename the\n// interface method so that the struct continues to implement it.\npub fn (r &ReferencesSearch) search_method(element psi.FunctionOrMethodDeclaration) []psi.PsiElement {\n\tiface_super_methods := super_methods(element)\n\tif iface_super_methods.len == 0 {\n\t\treturn r.search_named_element(element)\n\t}\n\n\tmut result := r.search_named_element(element)\n\tfor super_method in iface_super_methods {\n\t\tif super_method is psi.PsiNamedElement {\n\t\t\tresult << r.search_named_element(super_method)\n\t\t}\n\t}\n\n\treturn result\n}\n\npub fn (r &ReferencesSearch) search_generic_parameter(element psi.GenericParameter) []psi.PsiElement {\n\treturn r.search_private_named_element(element)\n}\n\npub fn (r &ReferencesSearch) search_module_import(element psi.PsiNamedElement) []psi.PsiElement {\n\tif r.params.only_in_current_file {\n\t\t// module cannot be imported in the same file where it is defined\n\t\treturn []\n\t}\n\n\tmut result := []psi.PsiElement{cap: 10}\n\tpsi_element := element as psi.PsiElement\n\tfile := psi_element.containing_file() or { return [] }\n\tfile_sink := file.index_sink() or { return [] }\n\tmodule_name := file_sink.module_fqn()\n\tdepends_sinks := stubs_index.get_all_sink_depends_on(module_name)\n\n\tfor sink in depends_sinks {\n\t\troot := sink.stub_list.index_map[0] or { continue }\n\t\tchildren := root.children_stubs()\n\t\tfor child in children {\n\t\t\tif child.stub_type() == .import_list {\n\t\t\t\tdeclarations := child.children_stubs()\n\t\t\t\tfor declaration in declarations {\n\t\t\t\t\timport_spec := declaration.first_child() or { continue }\n\t\t\t\t\timport_path := import_spec.first_child() or { continue }\n\t\t\t\t\tif import_path.stub_type() == .import_path {\n\t\t\t\t\t\tif import_path.text() == module_name {\n\t\t\t\t\t\t\tresult << import_path.get_psi() or { continue }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\npub fn (r &ReferencesSearch) search_named_element(element psi.PsiNamedElement) []psi.PsiElement {\n\tis_public := element.is_public()\n\tis_field := element is psi.FieldDeclaration\n\tif is_public || is_field {\n\t\treturn r.search_public_named_element(element)\n\t} else {\n\t\treturn r.search_private_named_element(element)\n\t}\n}\n\npub fn (r &ReferencesSearch) search_private_named_element(element psi.PsiNamedElement) []psi.PsiElement {\n\tmodule_name := r.containing_file.module_fqn()\n\treturn r.search_named_element_in_module(module_name, element)\n}\n\npub fn (r &ReferencesSearch) search_named_element_in_module(module_name string, element psi.PsiNamedElement) []psi.PsiElement {\n\tmut result := []psi.PsiElement{cap: 10}\n\tif r.params.include_declaration {\n\t\tresult << element as psi.PsiElement\n\t}\n\n\tif r.params.only_in_current_file {\n\t\tresult << r.search_in(element, r.containing_file.root())\n\t\treturn result\n\t}\n\n\tsinks_to_search := stubs_index.get_all_sinks_from_module(module_name)\n\tif sinks_to_search.len == 0 {\n\t\treturn []\n\t}\n\n\tmut path_to_search := []string{cap: sinks_to_search.len}\n\tfor sink in sinks_to_search {\n\t\tpath_to_search << sink.stub_list.path\n\t}\n\n\tcpus := runtime.nr_cpus()\n\tworkers := math.max(cpus - 2, 1)\n\tparsed_files := parser.parse_batch_files(path_to_search, workers)\n\n\tfor parsed_file in parsed_files {\n\t\tmut psi_file := psi.new_psi_file(parsed_file.path, parsed_file.tree,\n\t\t\tparsed_file.source_text)\n\t\tresult << r.search_in(element, psi_file.root)\n\t\tpsi_file.free()\n\t}\n\n\treturn result\n}\n\npub fn (r &ReferencesSearch) search_public_named_element(element psi.PsiNamedElement) []psi.PsiElement {\n\tif r.params.only_in_current_file {\n\t\tmut result := []psi.PsiElement{cap: 10}\n\t\tif r.params.include_declaration {\n\t\t\tresult << element as psi.PsiElement\n\t\t}\n\t\tresult << r.search_in(element, r.containing_file.root())\n\t\treturn result\n\t}\n\n\tfile_sink := r.containing_file.index_sink() or { return [] }\n\tmodule_name := file_sink.module_fqn()\n\n\t// we don't want to search symbol usages in the same module where it is defined\n\t// if this is not a workspace module\n\tusages_in_own_module := if file_sink.kind == .workspace {\n\t\tr.search_named_element_in_module(module_name, element)\n\t} else {\n\t\t[]psi.PsiElement{}\n\t}\n\n\tmut files := []string{cap: 10}\n\tdepends_sinks := stubs_index.get_all_sink_depends_on(module_name)\n\tfor sink in depends_sinks {\n\t\tif sink.kind != .workspace {\n\t\t\tcontinue\n\t\t}\n\n\t\tfiles << sink.stub_list.path\n\t}\n\n\tmut usages_in_depends_modules := []psi.PsiElement{cap: 10}\n\tcpus := runtime.nr_cpus()\n\tworkers := math.max(cpus - 2, 1)\n\n\twatch := time.new_stopwatch(auto_start: true)\n\tparsed_files := parser.parse_batch_files(files, workers)\n\tfor parsed_result in parsed_files {\n\t\tmut psi_file := psi.new_psi_file(parsed_result.path, parsed_result.tree,\n\t\t\tparsed_result.source_text)\n\t\tusages_in_depends_modules << r.search_in(element, psi_file.root)\n\t\tpsi_file.free()\n\t}\n\n\tloglib.with_duration(watch.elapsed()).info('Finish searching in depends modules')\n\n\tmut all_usages := []psi.PsiElement{cap: usages_in_own_module.len + usages_in_depends_modules.len}\n\tall_usages << usages_in_own_module\n\tall_usages << usages_in_depends_modules\n\treturn all_usages\n}\n\npub fn (r &ReferencesSearch) search_in_scope(element psi.PsiNamedElement, scope psi.PsiElement) []psi.PsiElement {\n\tmut result := []psi.PsiElement{cap: 10}\n\tif r.params.include_declaration {\n\t\tresult << element as psi.PsiElement\n\t}\n\n\t// looking for all references to a variable inside the scope\n\tresult << r.search_in(element, scope)\n\n\treturn result\n}\n\npub fn (r &ReferencesSearch) search_in(element psi.PsiNamedElement, search_root psi.PsiElement) []psi.PsiElement {\n\tname := element.name()\n\tmut result := []psi.PsiElement{cap: 10}\n\n\tmut walker := psi.new_psi_tree_walker(search_root)\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\tif node is psi.ReferenceExpression || node is psi.TypeReferenceExpression {\n\t\t\tref := node as psi.ReferenceExpressionBase\n\t\t\tif node.text_matches(name) {\n\t\t\t\tresolved := ref.resolve() or { continue }\n\t\t\t\tif resolved is psi.PsiNamedElement {\n\t\t\t\t\tif resolved.identifier_text_range() == element.identifier_text_range() {\n\t\t\t\t\t\tresult << node\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif element is psi.ImportSpec && resolved is psi.ImportSpec {\n\t\t\t\t\tif element.import_name() == resolved.import_name() {\n\t\t\t\t\t\tif element_file := element.containing_file() {\n\t\t\t\t\t\t\tif resolved_file := resolved.containing_file() {\n\t\t\t\t\t\t\t\tif element_file.path == resolved_file.path {\n\t\t\t\t\t\t\t\t\tresult << node\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\nfn resolve_identifier(element psi.PsiElement) ?psi.PsiElement {\n\tparent := element.parent()?\n\tresolved := if parent is psi.ReferenceExpression {\n\t\tparent.resolve()?\n\t} else if parent is psi.TypeReferenceExpression {\n\t\tparent.resolve()?\n\t} else {\n\t\tparent\n\t}\n\n\treturn resolved\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/common.v",
    "content": "module search\n\nimport analyzer.psi\nimport analyzer.psi.types\n\n// is_implemented checks if the given symbol (methods and fields) implements the given interface (methods and fields).\nfn is_implemented(iface_methods []psi.PsiElement, iface_fields []psi.PsiElement, symbol_methods []psi.PsiElement,\n\tsymbol_fields []psi.PsiElement) bool {\n\tmut symbol_methods_set := map[string]psi.FunctionOrMethodDeclaration{}\n\tfor symbol_method in symbol_methods {\n\t\tif symbol_method is psi.FunctionOrMethodDeclaration {\n\t\t\tsymbol_methods_set[symbol_method.fingerprint()] = *symbol_method\n\t\t}\n\t}\n\n\tfor iface_method in iface_methods {\n\t\tif iface_method is psi.InterfaceMethodDeclaration {\n\t\t\tif iface_method.fingerprint() !in symbol_methods_set {\n\t\t\t\t// if at least one method is not implemented, then the whole interface is not implemented\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tmut symbol_fields_set := map[string]psi.FieldDeclaration{}\n\tfor symbol_field in symbol_fields {\n\t\tif symbol_field is psi.FieldDeclaration {\n\t\t\tsymbol_fields_set[symbol_field.name()] = *symbol_field\n\t\t}\n\t}\n\n\tfor iface_field in iface_fields {\n\t\tif iface_field is psi.FieldDeclaration {\n\t\t\tif iface_field.is_embedded_definition() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif iface_field.name() !in symbol_fields_set {\n\t\t\t\t// if at least one field is not implemented, then the whole interface is not implemented\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tfor iface_method in iface_methods {\n\t\tif iface_method is psi.InterfaceMethodDeclaration {\n\t\t\tsymbol_method := symbol_methods_set[iface_method.fingerprint()] or { return false }\n\t\t\tif !is_method_compatible(*iface_method, symbol_method) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tfor iface_field in iface_fields {\n\t\tif iface_field is psi.FieldDeclaration {\n\t\t\tsymbol_field := symbol_fields_set[iface_field.name()] or { return false }\n\t\t\tif !is_field_compatible(*iface_field, symbol_field) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\nfn is_method_compatible(iface_method psi.InterfaceMethodDeclaration, symbol_method psi.FunctionOrMethodDeclaration) bool {\n\tiface_signature := iface_method.signature() or { return false }\n\tsymbol_signature := symbol_method.signature() or { return false }\n\n\tiface_type := iface_signature.get_type()\n\tsymbol_type := symbol_signature.get_type()\n\n\tif iface_type is types.FunctionType {\n\t\tif symbol_type is types.FunctionType {\n\t\t\tiface_params := iface_type.params\n\t\t\tsymbol_params := symbol_type.params\n\n\t\t\tif iface_params.len != symbol_params.len {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tfor i in 0 .. iface_params.len {\n\t\t\t\tif iface_params[i].qualified_name() != symbol_params[i].qualified_name() {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif iface_type.no_result != symbol_type.no_result {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif iface_type.result.qualified_name() != symbol_type.result.qualified_name() {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfn is_field_compatible(iface_field psi.FieldDeclaration, symbol_field psi.FieldDeclaration) bool {\n\tiface_type := iface_field.get_type()\n\tsymbol_type := symbol_field.get_type()\n\n\treturn iface_type.qualified_name() == symbol_type.qualified_name()\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/implementations.v",
    "content": "module search\n\nimport analyzer.psi\n\n// implementations returns all implementations of the given interface\n//\n// Search algorithm:\n// 1. Having interface methods and fields, we look for all methods and fields in structures with the same fingerprint.\n//    method fingerprint is the name + the number of parameters + the presence of a return value.\n//    field fingerprint is the name.\n//\n//    During indexing, we already collect all methods and fields into `.methods_fingerprint`\n//    and `.fields_fingerprint` indices, so searching for such methods and fields has a complexity of O(1).\n//\n// 2. For each received method and field, find the parent structure and add it to the list of candidates.\n//\n// 3. For each candidate, check that it implements all methods and fields of the interface.\npub fn implementations(iface psi.InterfaceDeclaration) []psi.PsiElement {\n\tmethods := iface.methods()\n\tfields := iface.fields()\n\n\tif methods.len == 0 && fields.len == 0 {\n\t\treturn []\n\t}\n\n\tcandidates := candidates_by_methods_and_fields(methods, fields)\n\tif candidates.len == 0 {\n\t\treturn []\n\t}\n\n\tmut result := map[string]psi.PsiElement{}\n\n\tfor candidate in candidates {\n\t\tname := candidate.name()\n\t\tif name in result {\n\t\t\t// don't check one candidate several times\n\t\t\tcontinue\n\t\t}\n\n\t\tif is_implemented_by_type(methods, fields, candidate as psi.PsiElement) {\n\t\t\tresult[name] = candidate as psi.PsiElement\n\t\t}\n\t}\n\n\treturn result.values()\n}\n\nfn is_implemented_by_type(iface_methods []psi.PsiElement, iface_fields []psi.PsiElement, symbol psi.PsiElement) bool {\n\tsymbol_type := if symbol is psi.PsiTypedElement {\n\t\tsymbol.get_type()\n\t} else {\n\t\treturn false\n\t}\n\n\tsymbol_methods := psi.methods_list(symbol_type)\n\tif symbol_methods.len == 0 && iface_methods.len != 0 {\n\t\treturn false\n\t}\n\tsymbol_fields := psi.fields_list(symbol_type)\n\tif symbol_fields.len == 0 && iface_fields.len != 0 {\n\t\treturn false\n\t}\n\n\treturn is_implemented(iface_methods, iface_fields, symbol_methods, symbol_fields)\n}\n\nfn candidates_by_methods_and_fields(methods []psi.PsiElement, fields []psi.PsiElement) []psi.PsiNamedElement {\n\tby_methods := candidates_by_methods(methods)\n\tby_fields := candidates_by_fields(fields)\n\tmut result := []psi.PsiNamedElement{cap: by_methods.len + by_fields.len}\n\tresult << by_methods\n\tresult << by_fields\n\treturn result\n}\n\nfn candidates_by_methods(methods []psi.PsiElement) []psi.PsiNamedElement {\n\tmut candidates := []psi.PsiNamedElement{cap: 5}\n\n\tfor method in methods {\n\t\tif method is psi.InterfaceMethodDeclaration {\n\t\t\tfingerprint := method.fingerprint()\n\n\t\t\t// all methods with the same fingerprint can probably be part of struct that implements the interface\n\t\t\tstruct_methods := stubs_index.get_elements_from_by_name(.workspace,\n\t\t\t\t.methods_fingerprint, fingerprint)\n\n\t\t\tfor struct_method in struct_methods {\n\t\t\t\tif struct_method is psi.FunctionOrMethodDeclaration {\n\t\t\t\t\towner := struct_method.owner() or { continue }\n\t\t\t\t\tif owner is psi.PsiNamedElement {\n\t\t\t\t\t\tcandidates << owner\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn candidates\n}\n\nfn candidates_by_fields(fields []psi.PsiElement) []psi.PsiNamedElement {\n\tmut candidates := []psi.PsiNamedElement{cap: 5}\n\n\tfor field in fields {\n\t\tif field is psi.FieldDeclaration {\n\t\t\tfingerprint := field.name()\n\n\t\t\t// all fields with the same fingerprint can probably be part of struct that implements the interface\n\t\t\tstruct_fields := stubs_index.get_elements_from_by_name(.workspace, .fields_fingerprint,\n\t\t\t\tfingerprint)\n\n\t\t\tfor struct_field in struct_fields {\n\t\t\t\tif struct_field is psi.FieldDeclaration {\n\t\t\t\t\towner := struct_field.owner() or { continue }\n\t\t\t\t\tif owner is psi.PsiNamedElement {\n\t\t\t\t\t\tcandidates << owner\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn candidates\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/implmenttion_methods.v",
    "content": "module search\n\nimport analyzer.psi\n\n// implementation_methods returns all methods that implement the given interface method.\npub fn implementation_methods(method psi.InterfaceMethodDeclaration) []psi.PsiElement {\n\tmut result := []psi.PsiElement{}\n\towner := method.owner() or { return [] }\n\tstructs := implementations(owner)\n\n\tfor struct_ in structs {\n\t\tif struct_ is psi.StructDeclaration {\n\t\t\tstruct_method := psi.find_method(struct_.get_type(), method.name()) or { continue }\n\t\t\tresult << struct_method\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/super_methods.v",
    "content": "module search\n\nimport analyzer.psi\n\n// super_methods returns interface methods that are implemented by the struct of given method.\npub fn super_methods(method psi.FunctionOrMethodDeclaration) []psi.PsiElement {\n\tmut result := []psi.PsiElement{}\n\n\tmethod_name := method.name()\n\towner := method.owner() or { return [] }\n\tif owner is psi.StructDeclaration {\n\t\tsuper_interfaces := supers(*owner)\n\t\tfor super_interface in super_interfaces {\n\t\t\tif super_interface is psi.InterfaceDeclaration {\n\t\t\t\tif iface_method := super_interface.find_method(method_name) {\n\t\t\t\t\tresult << iface_method\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "src/analyzer/psi/search/supers.v",
    "content": "module search\n\nimport analyzer.psi\n\n// supers returns all interfaces that are implemented by the given struct\n//\n// Search algorithm:\n// 1. Find all methods and fields of the struct\n// 2. Search for all interface methods and fields that have the same fingerprint\n//    (see description in `search.implementations()`)\n// 3. For each candidate, check that struct implements all methods and fields of the interface.\npub fn supers(strukt psi.StructDeclaration) []psi.PsiElement {\n\tstruct_type := strukt.get_type()\n\tmethods := psi.methods_list(struct_type)\n\tfields := strukt.fields()\n\n\tif methods.len == 0 && fields.len == 0 {\n\t\treturn []\n\t}\n\n\tcandidates := super_candidates_by_methods_and_fields(methods, fields)\n\tif candidates.len == 0 {\n\t\treturn []\n\t}\n\n\tmut result := map[string]psi.PsiElement{}\n\n\tfor candidate in candidates {\n\t\tname := candidate.name()\n\t\tif name in result {\n\t\t\t// don't check one candidate several times\n\t\t\tcontinue\n\t\t}\n\n\t\tif candidate is psi.InterfaceDeclaration {\n\t\t\tif is_implemented_interface(methods, fields, *candidate) {\n\t\t\t\tresult[name] = candidate\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.values()\n}\n\nfn is_implemented_interface(symbol_methods []psi.PsiElement, symbol_fields []psi.PsiElement, iface psi.InterfaceDeclaration) bool {\n\tiface_methods := iface.methods()\n\tiface_fields := iface.fields()\n\treturn is_implemented(iface_methods, iface_fields, symbol_methods, symbol_fields)\n}\n\nfn super_candidates_by_methods_and_fields(methods []psi.PsiElement, fields []psi.PsiElement) []psi.PsiNamedElement {\n\tby_methods := super_candidates_by_methods(methods)\n\tby_fields := super_candidates_by_fields(fields)\n\tmut result := []psi.PsiNamedElement{cap: by_methods.len + by_fields.len}\n\tresult << by_methods\n\tresult << by_fields\n\treturn result\n}\n\nfn super_candidates_by_methods(methods []psi.PsiElement) []psi.PsiNamedElement {\n\tmut candidates := []psi.PsiNamedElement{cap: 5}\n\n\tfor method in methods {\n\t\tif method is psi.FunctionOrMethodDeclaration {\n\t\t\tfingerprint := method.fingerprint()\n\n\t\t\t// all methods with the same fingerprint can probably be part of the same interface\n\t\t\tinterface_methods := stubs_index.get_elements_from_by_name(.workspace,\n\t\t\t\t.interface_methods_fingerprint, fingerprint)\n\n\t\t\tfor interface_method in interface_methods {\n\t\t\t\tif interface_method is psi.InterfaceMethodDeclaration {\n\t\t\t\t\tcandidates << interface_method.owner() or { continue }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn candidates\n}\n\nfn super_candidates_by_fields(fields []psi.PsiElement) []psi.PsiNamedElement {\n\tmut candidates := []psi.PsiNamedElement{cap: 5}\n\n\tfor field in fields {\n\t\tif field is psi.FieldDeclaration {\n\t\t\tfingerprint := field.name()\n\n\t\t\t// all fields with the same fingerprint can probably be part of interface that can be implemented by the struct\n\t\t\tinterface_fields := stubs_index.get_elements_from_by_name(.workspace,\n\t\t\t\t.interface_fields_fingerprint, fingerprint)\n\n\t\t\tfor interface_field in interface_fields {\n\t\t\t\tif interface_field is psi.FieldDeclaration {\n\t\t\t\t\towner := interface_field.owner() or { continue }\n\t\t\t\t\tif owner is psi.PsiNamedElement {\n\t\t\t\t\t\tcandidates << owner\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn candidates\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/AliasType.v",
    "content": "module types\n\npub struct AliasType {\n\tBaseNamedType\npub:\n\tinner Type\n}\n\npub fn new_alias_type(name string, module_name string, inner Type) &AliasType {\n\treturn &AliasType{\n\t\tname:        name\n\t\tmodule_name: module_name\n\t\tinner:       inner\n\t}\n}\n\npub fn (s &AliasType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &AliasType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_alias_type(s.name, s.module_name, s.inner.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/ArrayType.v",
    "content": "module types\n\npub struct ArrayType {\npub:\n\tinner Type\n}\n\npub fn new_array_type(inner Type) &ArrayType {\n\treturn &ArrayType{\n\t\tinner: inner\n\t}\n}\n\npub fn (s &ArrayType) name() string {\n\treturn '[]${s.inner.name()}'\n}\n\npub fn (s &ArrayType) qualified_name() string {\n\treturn '[]${s.inner.qualified_name()}'\n}\n\npub fn (s &ArrayType) readable_name() string {\n\treturn '[]${s.inner.readable_name()}'\n}\n\npub fn (s &ArrayType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &ArrayType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &ArrayType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_array_type(s.inner.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/BaseNamedType.v",
    "content": "module types\n\nstruct BaseNamedType {\npub:\n\tmodule_name string\n\tname        string\n}\n\npub fn (s &BaseNamedType) name() string {\n\treturn s.name\n}\n\npub fn (s &BaseNamedType) qualified_name() string {\n\tif s.module_name == '' {\n\t\treturn s.name\n\t}\n\treturn s.module_name + '.' + s.name\n}\n\npub fn (s &BaseNamedType) readable_name() string {\n\tif s.module_name == '' {\n\t\treturn s.name\n\t}\n\tlast_module := s.module_name.split('.').last()\n\tif last_module == 'builtin' || last_module == 'stubs' || last_module == 'main' {\n\t\treturn s.name\n\t}\n\treturn last_module + '.' + s.name\n}\n\npub fn (s &BaseNamedType) module_name() string {\n\treturn s.module_name\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/BaseType.v",
    "content": "module types\n\npub struct BaseType {\npub:\n\tmodule_name string\n}\n\n@[markused]\npub fn (s &BaseType) module_name() string {\n\treturn s.module_name\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/ChannelType.v",
    "content": "module types\n\npub struct ChannelType {\npub:\n\tinner Type\n}\n\npub fn new_channel_type(inner Type) &ChannelType {\n\treturn &ChannelType{\n\t\tinner: inner\n\t}\n}\n\npub fn (s &ChannelType) name() string {\n\treturn 'chan ${s.inner.name()}'\n}\n\npub fn (s &ChannelType) qualified_name() string {\n\treturn 'chan ${s.inner.qualified_name()}'\n}\n\npub fn (s &ChannelType) readable_name() string {\n\treturn 'chan ${s.inner.readable_name()}'\n}\n\npub fn (s &ChannelType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &ChannelType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &ChannelType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_channel_type(s.inner.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/EnumType.v",
    "content": "module types\n\npub struct EnumType {\n\tBaseNamedType\n}\n\npub fn new_enum_type(name string, module_name string) &EnumType {\n\treturn &EnumType{\n\t\tname:        name\n\t\tmodule_name: module_name\n\t}\n}\n\npub fn (s &EnumType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &EnumType) substitute_generics(_ map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/FixedArrayType.v",
    "content": "module types\n\npub struct FixedArrayType {\npub:\n\tinner Type\n\tsize  int\n}\n\npub fn new_fixed_array_type(inner Type, size int) &FixedArrayType {\n\treturn &FixedArrayType{\n\t\tinner: inner\n\t\tsize:  size\n\t}\n}\n\npub fn (s &FixedArrayType) name() string {\n\treturn '[${s.size}]${s.inner.name()}'\n}\n\npub fn (s &FixedArrayType) qualified_name() string {\n\treturn '[${s.size}]${s.inner.qualified_name()}'\n}\n\npub fn (s &FixedArrayType) readable_name() string {\n\treturn '[${s.size}]${s.inner.readable_name()}'\n}\n\npub fn (s &FixedArrayType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &FixedArrayType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &FixedArrayType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_fixed_array_type(s.inner.substitute_generics(name_map), s.size)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/FunctionType.v",
    "content": "module types\n\nimport strings\n\npub struct FunctionType {\n\tBaseType\npub:\n\tparams    []Type\n\tresult    Type\n\tno_result bool\n}\n\npub fn new_function_type(module_name string, params []Type, result Type, no_result bool) &FunctionType {\n\treturn &FunctionType{\n\t\tparams:      params\n\t\tresult:      result\n\t\tno_result:   no_result\n\t\tmodule_name: module_name\n\t}\n}\n\npub fn (s &FunctionType) name() string {\n\tmut sb := strings.new_builder(20)\n\tsb.write_string('fn (')\n\tfor index, param in s.params {\n\t\tsb.write_string(param.name())\n\t\tif index < s.params.len - 1 {\n\t\t\tsb.write_string(', ')\n\t\t}\n\t}\n\tsb.write_string(')')\n\tif !s.no_result {\n\t\tsb.write_string(' ')\n\t\tsb.write_string(s.result.name())\n\t}\n\n\treturn sb.str()\n}\n\npub fn (s &FunctionType) qualified_name() string {\n\tmut sb := strings.new_builder(20)\n\tsb.write_string('fn (')\n\tfor index, param in s.params {\n\t\tsb.write_string(param.qualified_name())\n\t\tif index < s.params.len - 1 {\n\t\t\tsb.write_string(', ')\n\t\t}\n\t}\n\tsb.write_string(')')\n\tif !s.no_result {\n\t\tsb.write_string(' ')\n\t\tsb.write_string(s.result.qualified_name())\n\t}\n\n\treturn sb.str()\n}\n\npub fn (s &FunctionType) readable_name() string {\n\tmut sb := strings.new_builder(20)\n\tsb.write_string('fn (')\n\tfor index, param in s.params {\n\t\tsb.write_string(param.readable_name())\n\t\tif index < s.params.len - 1 {\n\t\t\tsb.write_string(', ')\n\t\t}\n\t}\n\tsb.write_string(')')\n\tif !s.no_result {\n\t\tsb.write_string(' ')\n\t\tsb.write_string(s.result.readable_name())\n\t}\n\n\treturn sb.str()\n}\n\npub fn (s &FunctionType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\tfor param in s.params {\n\t\tparam.accept(mut visitor)\n\t}\n\n\ts.result.accept(mut visitor)\n}\n\npub fn (s &FunctionType) substitute_generics(name_map map[string]Type) Type {\n\tparams := s.params.map(it.substitute_generics(name_map))\n\tresult := s.result.substitute_generics(name_map)\n\treturn new_function_type(s.module_name, params, result, s.no_result)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/GenericInstantiationType.v",
    "content": "module types\n\npub struct GenericInstantiationType {\npub:\n\tinner          Type\n\tspecialization []Type\n}\n\npub fn new_generic_instantiation_type(inner Type, specialization []Type) &GenericInstantiationType {\n\treturn &GenericInstantiationType{\n\t\tinner:          inner\n\t\tspecialization: specialization\n\t}\n}\n\npub fn (s &GenericInstantiationType) name() string {\n\treturn '${s.inner.name()}[${s.specialization.map(it.name()).join(', ')}]'\n}\n\npub fn (s &GenericInstantiationType) qualified_name() string {\n\treturn '${s.inner.qualified_name()}[${s.specialization.map(it.qualified_name()).join(', ')}]'\n}\n\npub fn (s &GenericInstantiationType) readable_name() string {\n\treturn '${s.inner.readable_name()}[${s.specialization.map(it.readable_name()).join(', ')}]'\n}\n\npub fn (s &GenericInstantiationType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &GenericInstantiationType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n\n\tfor specialization in s.specialization {\n\t\tspecialization.accept(mut visitor)\n\t}\n}\n\npub fn (s &GenericInstantiationType) substitute_generics(name_map map[string]Type) Type {\n\tinner := s.inner.substitute_generics(name_map)\n\tspecialization := s.specialization.map(it.substitute_generics(name_map))\n\treturn new_generic_instantiation_type(inner, specialization)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/GenericType.v",
    "content": "module types\n\npub struct GenericType {\n\tBaseNamedType\n}\n\npub fn new_generic_type(name string) &GenericType {\n\treturn &GenericType{\n\t\tname: name\n\t}\n}\n\npub fn (s &GenericType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &GenericType) substitute_generics(name_map map[string]Type) Type {\n\treturn name_map[s.name] or { return s }\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/InterfaceType.v",
    "content": "module types\n\npub struct InterfaceType {\n\tBaseNamedType\n}\n\npub fn new_interface_type(name string, module_name string) &InterfaceType {\n\treturn &InterfaceType{\n\t\tname:        name\n\t\tmodule_name: module_name\n\t}\n}\n\npub fn (s &InterfaceType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &InterfaceType) substitute_generics(name_map map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/MapType.v",
    "content": "module types\n\npub struct MapType {\n\tBaseType\npub:\n\tkey   Type\n\tvalue Type\n}\n\npub fn new_map_type(module_name string, key Type, value Type) &MapType {\n\treturn &MapType{\n\t\tkey:         key\n\t\tvalue:       value\n\t\tmodule_name: module_name\n\t}\n}\n\npub fn (s &MapType) name() string {\n\treturn 'map[${s.key.name()}]${s.value.name()}'\n}\n\npub fn (s &MapType) qualified_name() string {\n\treturn 'map[${s.key.name()}]${s.value.qualified_name()}'\n}\n\npub fn (s &MapType) readable_name() string {\n\treturn 'map[${s.key.name()}]${s.value.readable_name()}'\n}\n\npub fn (s &MapType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.key.accept(mut visitor)\n\ts.value.accept(mut visitor)\n}\n\npub fn (s &MapType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_map_type(s.module_name, s.key.substitute_generics(name_map),\n\t\ts.value.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/MultiReturnType.v",
    "content": "module types\n\npub struct MultiReturnType {\npub:\n\ttypes []Type\n}\n\npub fn new_multi_return_type(types []Type) &MultiReturnType {\n\treturn &MultiReturnType{\n\t\ttypes: types\n\t}\n}\n\npub fn (s &MultiReturnType) name() string {\n\treturn '(${s.types.map(it.name()).join(', ')})'\n}\n\npub fn (s &MultiReturnType) qualified_name() string {\n\treturn '(${s.types.map(it.qualified_name()).join(', ')})'\n}\n\npub fn (s &MultiReturnType) readable_name() string {\n\treturn '(${s.types.map(it.readable_name()).join(', ')})'\n}\n\npub fn (s &MultiReturnType) module_name() string {\n\treturn ''\n}\n\npub fn (s &MultiReturnType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\tfor type_ in s.types {\n\t\ttype_.accept(mut visitor)\n\t}\n}\n\npub fn (s &MultiReturnType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_multi_return_type(s.types.map(it.substitute_generics(name_map)))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/OptionType.v",
    "content": "module types\n\npub struct OptionType {\npub:\n\tinner    Type\n\tno_inner bool\n}\n\npub fn new_option_type(inner Type, no_inner bool) &OptionType {\n\treturn &OptionType{\n\t\tinner:    inner\n\t\tno_inner: no_inner\n\t}\n}\n\npub fn (s &OptionType) name() string {\n\tif s.no_inner {\n\t\treturn '?'\n\t}\n\treturn '?${s.inner.name()}'\n}\n\npub fn (s &OptionType) qualified_name() string {\n\tif s.no_inner {\n\t\treturn '?'\n\t}\n\treturn '?${s.inner.qualified_name()}'\n}\n\npub fn (s &OptionType) readable_name() string {\n\tif s.no_inner {\n\t\treturn '?'\n\t}\n\treturn '?${s.inner.readable_name()}'\n}\n\npub fn (s &OptionType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &OptionType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &OptionType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_option_type(s.inner.substitute_generics(name_map), s.no_inner)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/PointerType.v",
    "content": "module types\n\npub struct PointerType {\npub:\n\tinner Type\n}\n\npub fn new_pointer_type(inner Type) &PointerType {\n\treturn &PointerType{\n\t\tinner: inner\n\t}\n}\n\npub fn (s &PointerType) name() string {\n\treturn '&${s.inner.name()}'\n}\n\npub fn (s &PointerType) qualified_name() string {\n\treturn '&${s.inner.qualified_name()}'\n}\n\npub fn (s &PointerType) readable_name() string {\n\treturn '&${s.inner.readable_name()}'\n}\n\npub fn (s &PointerType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &PointerType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &PointerType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_pointer_type(s.inner.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/PrimitiveType.v",
    "content": "module types\n\npub struct PrimitiveType {\npub:\n\tname string\n}\n\npub fn new_primitive_type(name string) &PrimitiveType {\n\treturn &PrimitiveType{\n\t\tname: name\n\t}\n}\n\nfn (s &PrimitiveType) name() string {\n\treturn s.name\n}\n\nfn (s &PrimitiveType) qualified_name() string {\n\treturn s.name\n}\n\nfn (s &PrimitiveType) readable_name() string {\n\treturn s.name\n}\n\npub fn (s &PrimitiveType) module_name() string {\n\treturn 'builtin'\n}\n\npub fn is_primitive_type(typ string) bool {\n\treturn typ in ['i8', 'i16', 'i32', 'int', 'i64', 'byte', 'u8', 'u16', 'u32', 'u64', 'f32',\n\t\t'f64', 'char', 'bool', 'rune', 'usize', 'isize']\n}\n\npub fn (s &PrimitiveType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &PrimitiveType) substitute_generics(name_map map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/ResultType.v",
    "content": "module types\n\npub struct ResultType {\npub:\n\tinner    Type\n\tno_inner bool\n}\n\npub fn new_result_type(inner Type, no_inner bool) &ResultType {\n\treturn &ResultType{\n\t\tinner:    inner\n\t\tno_inner: no_inner\n\t}\n}\n\npub fn (s &ResultType) name() string {\n\tif s.no_inner {\n\t\treturn '!'\n\t}\n\treturn '!${s.inner.name()}'\n}\n\npub fn (s &ResultType) qualified_name() string {\n\tif s.no_inner {\n\t\treturn '!'\n\t}\n\treturn '!${s.inner.qualified_name()}'\n}\n\npub fn (s &ResultType) readable_name() string {\n\tif s.no_inner {\n\t\treturn '!'\n\t}\n\treturn '!${s.inner.readable_name()}'\n}\n\npub fn (s &ResultType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &ResultType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &ResultType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_result_type(s.inner.substitute_generics(name_map), s.no_inner)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/StructType.v",
    "content": "module types\n\npub const string_type = new_struct_type('string', 'builtin')\npub const builtin_array_type = new_struct_type('array', 'builtin')\npub const builtin_map_type = new_struct_type('map', 'builtin')\npub const array_init_type = new_struct_type('ArrayInit', 'stubs')\npub const chan_init_type = new_struct_type('ChanInit', 'stubs')\npub const flag_enum_type = new_enum_type('FlagEnum', 'stubs')\npub const any_type = new_alias_type('Any', 'stubs', unknown_type)\n\npub struct StructType {\n\tBaseNamedType\n}\n\npub fn new_struct_type(name string, module_name string) &StructType {\n\treturn &StructType{\n\t\tname:        name\n\t\tmodule_name: module_name\n\t}\n}\n\npub fn (s &StructType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &StructType) substitute_generics(name_map map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/ThreadType.v",
    "content": "module types\n\npub struct ThreadType {\n\tinner Type\n}\n\npub fn new_thread_type(inner Type) &ThreadType {\n\treturn &ThreadType{\n\t\tinner: inner\n\t}\n}\n\npub fn (s &ThreadType) name() string {\n\treturn 'thread ${s.inner.name()}'\n}\n\npub fn (s &ThreadType) qualified_name() string {\n\treturn 'thread ${s.inner.qualified_name()}'\n}\n\npub fn (s &ThreadType) readable_name() string {\n\treturn 'thread ${s.inner.readable_name()}'\n}\n\npub fn (s &ThreadType) module_name() string {\n\treturn s.inner.module_name()\n}\n\npub fn (s &ThreadType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n\n\ts.inner.accept(mut visitor)\n}\n\npub fn (s &ThreadType) substitute_generics(name_map map[string]Type) Type {\n\treturn new_thread_type(s.inner.substitute_generics(name_map))\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/Type.v",
    "content": "module types\n\npub interface Type {\n\tname() string\n\tqualified_name() string\n\treadable_name() string\n\tmodule_name() string\n\tsubstitute_generics(name_map map[string]Type) Type\n\taccept(mut visitor TypeVisitor)\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/TypeVisitor.v",
    "content": "module types\n\npub interface TypeVisitor {\nmut:\n\tenter(typ Type) bool\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/UnknownType.v",
    "content": "module types\n\npub const unknown_type = new_unknown_type()\n\npub struct UnknownType {}\n\n// new_unknown_type creates a new unknown type.\n// Use `unknown_type` constant instead.\nfn new_unknown_type() &UnknownType {\n\treturn &UnknownType{}\n}\n\nfn (_ &UnknownType) name() string {\n\treturn 'unknown'\n}\n\nfn (_ &UnknownType) qualified_name() string {\n\treturn 'unknown'\n}\n\nfn (_ &UnknownType) readable_name() string {\n\treturn 'unknown'\n}\n\nfn (_ &UnknownType) module_name() string {\n\treturn ''\n}\n\npub fn (s &UnknownType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &UnknownType) substitute_generics(name_map map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/VoidPtrType.v",
    "content": "module types\n\npub const voidptr_type = new_voidptr_type()\n\npub struct VoidPtrType {}\n\nfn new_voidptr_type() &VoidPtrType {\n\treturn &VoidPtrType{}\n}\n\nfn (_ &VoidPtrType) name() string {\n\treturn 'voidptr'\n}\n\nfn (_ &VoidPtrType) qualified_name() string {\n\treturn 'voidptr'\n}\n\nfn (_ &VoidPtrType) readable_name() string {\n\treturn 'voidptr'\n}\n\nfn (_ &VoidPtrType) module_name() string {\n\treturn ''\n}\n\npub fn (s &VoidPtrType) accept(mut visitor TypeVisitor) {\n\tif !visitor.enter(s) {\n\t\treturn\n\t}\n}\n\npub fn (s &VoidPtrType) substitute_generics(name_map map[string]Type) Type {\n\treturn s\n}\n"
  },
  {
    "path": "src/analyzer/psi/types/helpers.v",
    "content": "module types\n\npub fn unwrap_pointer_type(typ Type) Type {\n\tif typ is PointerType {\n\t\treturn typ.inner\n\t}\n\treturn typ\n}\n\npub fn unwrap_alias_type(typ Type) Type {\n\tif typ is AliasType {\n\t\treturn typ.inner\n\t}\n\treturn typ\n}\n\npub fn unwrap_channel_type(typ Type) Type {\n\tif typ is ChannelType {\n\t\treturn typ.inner\n\t}\n\treturn typ\n}\n\npub fn unwrap_result_or_option_type(typ Type) Type {\n\tif typ is ResultType {\n\t\treturn typ.inner\n\t}\n\tif typ is OptionType {\n\t\treturn typ.inner\n\t}\n\treturn typ\n}\n\npub fn unwrap_result_or_option_type_if(typ Type, condition bool) Type {\n\tif condition {\n\t\treturn unwrap_result_or_option_type(typ)\n\t}\n\treturn typ\n}\n\npub fn unwrap_generic_instantiation_type(typ Type) Type {\n\tif typ is GenericInstantiationType {\n\t\treturn typ.inner\n\t}\n\treturn typ\n}\n\npub fn is_builtin_array_type(typ Type) bool {\n\tif typ is StructType {\n\t\treturn typ.qualified_name() == builtin_array_type.qualified_name()\n\t}\n\treturn false\n}\n\npub fn is_builtin_map_type(typ Type) bool {\n\tif typ is StructType {\n\t\treturn typ.qualified_name() == builtin_map_type.qualified_name()\n\t}\n\treturn false\n}\n\nstruct IsGenericVisitor {\nmut:\n\tis_generic bool\n}\n\nfn (mut v IsGenericVisitor) enter(typ Type) bool {\n\tif typ is GenericType {\n\t\tv.is_generic = true\n\t\treturn false\n\t}\n\treturn true\n}\n\npub fn is_generic(typ Type) bool {\n\tif typ is GenericType {\n\t\treturn true\n\t}\n\n\tmut v := IsGenericVisitor{}\n\ttyp.accept(mut v)\n\treturn v.is_generic\n}\n"
  },
  {
    "path": "src/analyzer/psi/types_util.v",
    "content": "module psi\n\nimport analyzer.psi.types\n\npub fn own_methods_list(typ types.Type) []PsiElement {\n\tmodule_name := typ.module_name()\n\tname := typ.name()\n\tif module_name == '' || name == '' {\n\t\treturn []\n\t}\n\n\tkey := '${module_name}.${name}'\n\tmethods := stubs_index.get_elements_by_name(.methods, key)\n\treturn methods\n}\n\npub fn fields_list(typ types.Type) []PsiElement {\n\tname := typ.qualified_name()\n\tstructs := stubs_index.get_elements_by_name(.structs, name)\n\tif structs.len == 0 {\n\t\treturn []\n\t}\n\n\tstruct_ := structs.first()\n\tif struct_ is StructDeclaration {\n\t\treturn struct_.fields()\n\t}\n\treturn []\n}\n\npub fn methods_list(typ types.Type) []PsiElement {\n\tmut result := own_methods_list(typ)\n\n\tunwrapped := types.unwrap_alias_type(types.unwrap_pointer_type(typ))\n\tif unwrapped.qualified_name() != typ.qualified_name() {\n\t\t// if after unwrapping alias type we get another type, we need\n\t\t// to collect their methods as well.\n\t\tresult << own_methods_list(unwrapped)\n\t}\n\n\tif typ is types.InterfaceType {\n\t\tif interface_ := find_interface(typ.qualified_name()) {\n\t\t\tembedded_types := interface_.embedded_definitions().map(it.get_type())\n\t\t\tfor embedded_type in embedded_types {\n\t\t\t\tresult << methods_list(embedded_type)\n\t\t\t}\n\t\t}\n\t}\n\n\tif typ is types.StructType {\n\t\tif struct_ := find_struct(typ.qualified_name()) {\n\t\t\tembedded_types := struct_.embedded_definitions().map(it.get_type())\n\t\t\tfor embedded_type in embedded_types {\n\t\t\t\tresult << methods_list(embedded_type)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\npub fn find_method(typ types.Type, name string) ?PsiElement {\n\tmethods := methods_list(typ)\n\tfor method in methods {\n\t\tif method is PsiNamedElement {\n\t\t\tif method.name() == name {\n\t\t\t\treturn method as PsiElement\n\t\t\t}\n\t\t}\n\t}\n\treturn none\n}\n\npub fn static_methods_list(typ types.Type) []PsiElement {\n\tmodule_name := typ.module_name()\n\tname := typ.name()\n\tif module_name == '' || name == '' {\n\t\treturn []\n\t}\n\n\tkey := '${module_name}.${name}'\n\tmethods := stubs_index.get_elements_by_name(.static_methods, key)\n\treturn methods\n}\n"
  },
  {
    "path": "src/analyzer/psi/utils.v",
    "content": "module psi\n\npub fn get_it_call(element PsiElement) ?&CallExpression {\n\tmut parent_call := element.parent_of_type(.call_expression)?\n\tif mut parent_call is CallExpression {\n\t\tfor {\n\t\t\texpression := parent_call.expression() or { break }\n\t\t\tif expression.is_parent_of(element) {\n\t\t\t\t// when it used as expression of call\n\t\t\t\t// it.foo()\n\t\t\t\tparent_call = parent_call.parent_of_type(.call_expression) or { break }\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tmethods_names := ['filter', 'map', 'any', 'all']\n\tif mut parent_call is CallExpression && is_array_method_call(parent_call, ...methods_names) {\n\t\treturn parent_call\n\t}\n\n\treturn none\n}\n\npub fn is_array_method_call(element CallExpression, names ...string) bool {\n\tref_expression := element.ref_expression() or { return false }\n\tlast_child := (ref_expression as PsiElement).last_child() or { return false }\n\tcalled_name := last_child.get_text()\n\treturn called_name in names\n}\n"
  },
  {
    "path": "src/analyzer/psi/walk.v",
    "content": "module psi\n\n// inspect traverses an AST in depth-first order: It starts by calling\n// `cb(node)`; node must not be `nil`. If call returns `true`, `inspect` invokes `cb`\n// recursively for each of the non-nil children of node. Otherwise, `inspect` skips\n// the children of node.\n//\n// Example:\n// ```\n// inspect(root, fn (node PsiElement) bool {\n//   match node {\n//     psi.FunctionDeclaration {\n//       println('function ${node.name()}')\n//     }\n//     else {}\n//   }\n//   return true\n// })\npub fn inspect(node PsiElement, cb fn (PsiElement) bool) {\n\tinspector := Inspector{\n\t\tcb: cb\n\t}\n\tnode.accept(inspector)\n}\n\nstruct Inspector {\n\tcb fn (src.analyzer.psi.PsiElement) bool = unsafe { nil }\n}\n\nfn (r &Inspector) visit_element(element PsiElement) {\n\tif !r.visit_element_impl(element) {\n\t\treturn\n\t}\n\tmut child := element.first_child() or { return }\n\tfor {\n\t\tchild.accept(r)\n\t\tchild = child.next_sibling() or { break }\n\t}\n}\n\nfn (i &Inspector) visit_element_impl(element PsiElement) bool {\n\treturn i.cb(create_element(element.node(), element.containing_file()))\n}\n"
  },
  {
    "path": "src/bytes/README.md",
    "content": "# Description\n\n`bytes` module implements serialization and deserialization data to bytes.\n"
  },
  {
    "path": "src/bytes/deserialize.v",
    "content": "module bytes\n\npub struct Deserializer {\nmut:\n\tindex int\n\tdata  []u8\n}\n\npub fn new_deserializer(data []u8) Deserializer {\n\treturn Deserializer{\n\t\tdata: data\n\t}\n}\n\npub fn (mut s Deserializer) read_string() string {\n\tlen := s.read_int()\n\tif len == 0 {\n\t\treturn ''\n\t}\n\n\tdata := s.data[s.index..s.index + len]\n\ts.index += len\n\treturn data.bytestr()\n}\n\npub fn (mut s Deserializer) read_int() int {\n\tfirst := s.read_u8()\n\tif first == 1 {\n\t\treturn s.read_u8()\n\t}\n\n\tdata := s.data[s.index..s.index + 4]\n\ts.index += 4\n\tmut res := 0\n\tfor index, datum in data {\n\t\tres |= datum << (8 * (3 - index))\n\t}\n\treturn res\n}\n\npub fn (mut s Deserializer) read_i64() i64 {\n\tdata := s.data[s.index..s.index + 8]\n\ts.index += 8\n\tmut res := 0\n\tfor index, datum in data {\n\t\tres |= datum << (8 * (7 - index))\n\t}\n\treturn res\n}\n\n@[inline]\npub fn (mut s Deserializer) read_u8() u8 {\n\tindex := s.index\n\ts.index++\n\treturn s.data[index]\n}\n"
  },
  {
    "path": "src/bytes/serialization_test.v",
    "content": "module bytes\n\nfn test_serialize_deserialize() {\n\tmut s := Serializer{}\n\ts.write_string('hello')\n\ts.write_int(560000)\n\n\tmut d := Deserializer{\n\t\tdata: s.data\n\t}\n\tassert d.read_string() == 'hello'\n\tassert d.read_int() == 560000\n}\n\nfn test_serialize_deserialize_several_strings() {\n\tmut s := Serializer{}\n\ts.write_string('hello')\n\ts.write_string('world')\n\n\tmut d := Deserializer{\n\t\tdata: s.data\n\t}\n\tassert d.read_string() == 'hello'\n\tassert d.read_string() == 'world'\n}\n\nfn test_serialize_deserialize_stub_element() {\n\tmut s := Serializer{}\n\tdata := StubBase{\n\t\tname:       'test'\n\t\ttext_range: TextRange{\n\t\t\tline:       1\n\t\t\tcolumn:     2\n\t\t\tend_line:   3\n\t\t\tend_column: 4\n\t\t}\n\t\tstub_type:  .function_declaration\n\t\tid:         123456\n\t\ttext:       'some text with spaces'\n\t\tcomment:    '// comment data'\n\t\treceiver:   'Foo'\n\t}\n\n\tserialize_stub_element(mut s, data)\n\n\tprintln(s.data.bytestr())\n\n\tmut d := Deserializer{\n\t\tdata: s.data\n\t}\n\tdata2 := deserialize_stub_element(mut d)\n\n\tassert data2.name == data.name\n\tassert data2.text_range.line == data.text_range.line\n\tassert data2.text_range.column == data.text_range.column\n\tassert data2.text_range.end_line == data.text_range.end_line\n\tassert data2.text_range.end_column == data.text_range.end_column\n\tassert data2.stub_type == data.stub_type\n\tassert data2.id == data.id\n\tassert data2.text == data.text\n\tassert data2.comment == data.comment\n\tassert data2.receiver == data.receiver\n}\n\nfn serialize_stub_element(mut s Serializer, stub StubBase) {\n\ts.write_string(stub.name)\n\ts.write_int(stub.text_range.line)\n\ts.write_int(stub.text_range.column)\n\ts.write_int(stub.text_range.end_line)\n\ts.write_int(stub.text_range.end_column)\n\ts.write_u8(u8(stub.stub_type))\n\ts.write_int(stub.id)\n\ts.write_string(stub.text)\n\ts.write_string(stub.comment)\n\ts.write_string(stub.receiver)\n}\n\nfn deserialize_stub_element(mut s Deserializer) StubBase {\n\tname := s.read_string()\n\ttext_range := TextRange{\n\t\tline:       s.read_int()\n\t\tcolumn:     s.read_int()\n\t\tend_line:   s.read_int()\n\t\tend_column: s.read_int()\n\t}\n\tstub_type := unsafe { StubType(s.read_u8()) }\n\tid := s.read_int()\n\ttext := s.read_string()\n\tcomment := s.read_string()\n\treceiver := s.read_string()\n\n\treturn StubBase{\n\t\tname:       name\n\t\ttext_range: text_range\n\t\tstub_type:  stub_type\n\t\tid:         id\n\t\ttext:       text\n\t\tcomment:    comment\n\t\treceiver:   receiver\n\t}\n}\n\npub type StubId = int\n\npub struct StubData {\npub:\n\ttext     string\n\tcomment  string\n\treceiver string\n}\n\npub struct StubBase {\n\tStubData\npub:\n\tname       string\n\ttext_range TextRange\n\t// stub_list  &StubList\n\t// parent     &StubElement\n\tstub_type StubType\npub mut:\n\tid StubId\n}\n\npub struct TextRange {\npub:\n\tline       int\n\tcolumn     int\n\tend_line   int\n\tend_column int\n}\n\npub enum StubType as u8 {\n\troot\n\tfunction_declaration\n\tmethod_declaration\n\treceiver\n\tsignature\n\tstruct_declaration\n\tenum_declaration\n\tfield_declaration\n\tstruct_field_scope\n\tenum_field_definition\n\tconstant_declaration\n\ttype_alias_declaration\n\tattributes\n\tattribute\n\tattribute_expression\n\tvalue_attribute\n\tplain_type\n}\n"
  },
  {
    "path": "src/bytes/serialize.v",
    "content": "module bytes\n\npub struct Serializer {\npub mut:\n\tdata []u8\n}\n\n@[inline]\npub fn (mut s Serializer) write_u8(data u8) {\n\ts.data << data\n}\n\n@[inline]\npub fn (mut s Serializer) write_string(str string) {\n\ts.write_int(str.len)\n\tunsafe { s.data.push_many(str.str, str.len) }\n}\n\npub fn (mut s Serializer) write_int(data int) {\n\tif data > 0 && data < 0xff {\n\t\ts.data << 1\n\t\ts.data << u8(data)\n\t\treturn\n\t}\n\ts.data << 0\n\tfor i in 0 .. 4 {\n\t\ts.data << u8(data >> (8 * (3 - i))) & 0xff\n\t}\n}\n\npub fn (mut s Serializer) write_i64(data i64) {\n\tfor i in 0 .. 8 {\n\t\ts.data << u8(data >> (8 * (7 - i))) & 0xff\n\t}\n}\n"
  },
  {
    "path": "src/check-updates.v",
    "content": "module main\n\nimport cli\n\nfn check_updates_cmd(_ cli.Command) ! {\n\tdownload_install_vsh()!\n\tcall_install_vsh('check-updates')!\n}\n"
  },
  {
    "path": "src/clear-cache.v",
    "content": "module main\n\nimport cli\nimport os\nimport config\n\nfn clear_cache_cmd(_ cli.Command) ! {\n\tglobal_config_path := config.analyzer_caches_path\n\tif !os.exists(global_config_path) {\n\t\twarnln('No global cache found at: ${global_config_path}')\n\t\treturn\n\t}\n\n\tif !os.is_dir(global_config_path) {\n\t\twarnln('Global cache directory is not a directory: ${global_config_path}')\n\t\treturn\n\t}\n\n\tprintln('Clearing cache...')\n\tprintln('Found global cache at: ${global_config_path}')\n\n\tos.rmdir_all(global_config_path) or { errorln('Failed to clear cache: ${err}') }\n\n\tsuccessln('Cache cleared')\n}\n"
  },
  {
    "path": "src/config/EditorConfig.v",
    "content": "module config\n\nimport toml\n\npub enum SemanticTokensMode {\n\tfull\n\tsyntax\n\tnone_\n}\n\npub struct InlayHintsConfig {\npub mut:\n\tenable                        bool = true\n\tenable_range_hints            bool = true\n\tenable_type_hints             bool = true\n\tenable_implicit_err_hints     bool = true\n\tenable_parameter_name_hints   bool = true\n\tenable_constant_type_hints    bool = true\n\tenable_enum_field_value_hints bool = true\n}\n\npub struct CodeLensConfig {\npub mut:\n\tenable                       bool = true\n\tenable_run_lens              bool = true\n\tenable_inheritors_lens       bool = true\n\tenable_super_interfaces_lens bool = true\n\tenable_run_tests_lens        bool = true\n}\n\npub struct EditorConfig {\npub:\n\troot string\n\tpath string\npub mut:\n\tcustom_vroot           string\n\tcustom_cache_dir       string\n\tinlay_hints            InlayHintsConfig\n\tenable_semantic_tokens SemanticTokensMode = SemanticTokensMode.full\n\tcode_lens              CodeLensConfig\n}\n\npub fn from_toml(root string, path string, content string) !EditorConfig {\n\tmut econfig := EditorConfig{\n\t\troot: root\n\t\tpath: path\n\t}\n\n\tres := toml.parse_text(content)!\n\n\tcustom_vroot_value := res.value('custom_vroot')\n\tif custom_vroot_value is string {\n\t\teconfig.custom_vroot = custom_vroot_value\n\t}\n\n\tcustom_cache_dir := res.value('custom_cache_dir')\n\tif custom_cache_dir is string {\n\t\teconfig.custom_cache_dir = custom_cache_dir\n\t}\n\n\tenable_semantic_tokens := res.value('enable_semantic_tokens')\n\tif enable_semantic_tokens is string {\n\t\teconfig.enable_semantic_tokens = match enable_semantic_tokens {\n\t\t\t'full' { SemanticTokensMode.full }\n\t\t\t'syntax' { SemanticTokensMode.syntax }\n\t\t\t'none' { SemanticTokensMode.none_ }\n\t\t\telse { SemanticTokensMode.full }\n\t\t}\n\t}\n\n\tinlay_hints_table := res.value('inlay_hints')\n\tenable_value := inlay_hints_table.value('enable')\n\teconfig.inlay_hints.enable = if enable_value is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_value.bool()\n\t}\n\n\tenable_range_hints_value := inlay_hints_table.value('enable_range_hints')\n\teconfig.inlay_hints.enable_range_hints = if enable_range_hints_value is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_range_hints_value.bool()\n\t}\n\n\tenable_type_hints_value := inlay_hints_table.value('enable_type_hints')\n\teconfig.inlay_hints.enable_type_hints = if enable_type_hints_value is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_type_hints_value.bool()\n\t}\n\n\tenable_implicit_err_hints := inlay_hints_table.value('enable_implicit_err_hints')\n\teconfig.inlay_hints.enable_implicit_err_hints = if enable_implicit_err_hints is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_implicit_err_hints.bool()\n\t}\n\n\tenable_parameter_name_hints := inlay_hints_table.value('enable_parameter_name_hints')\n\teconfig.inlay_hints.enable_parameter_name_hints = if enable_parameter_name_hints is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_parameter_name_hints.bool()\n\t}\n\n\tenable_constant_type_hints := inlay_hints_table.value('enable_constant_type_hints')\n\teconfig.inlay_hints.enable_constant_type_hints = if enable_constant_type_hints is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_constant_type_hints.bool()\n\t}\n\n\tenable_enum_field_value_hints := inlay_hints_table.value('enable_enum_field_value_hints')\n\teconfig.inlay_hints.enable_enum_field_value_hints = if enable_enum_field_value_hints is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_enum_field_value_hints.bool()\n\t}\n\n\tcode_lens_table := res.value('code_lens')\n\tenable_lens_value := code_lens_table.value('enable')\n\teconfig.code_lens.enable = if enable_lens_value is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_lens_value.bool()\n\t}\n\n\tenable_run_lens := code_lens_table.value('enable_run_lens')\n\teconfig.code_lens.enable_run_lens = if enable_run_lens is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_run_lens.bool()\n\t}\n\n\tenable_inheritors_lens := code_lens_table.value('enable_inheritors_lens')\n\teconfig.code_lens.enable_inheritors_lens = if enable_inheritors_lens is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_inheritors_lens.bool()\n\t}\n\n\tenable_super_interfaces_lens := code_lens_table.value('enable_super_interfaces_lens')\n\teconfig.code_lens.enable_super_interfaces_lens = if enable_super_interfaces_lens is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_super_interfaces_lens.bool()\n\t}\n\n\tenable_run_tests_lens := code_lens_table.value('enable_run_tests_lens')\n\teconfig.code_lens.enable_run_tests_lens = if enable_run_tests_lens is toml.Null {\n\t\ttrue // default to true\n\t} else {\n\t\tenable_run_tests_lens.bool()\n\t}\n\n\treturn econfig\n}\n\npub fn (e &EditorConfig) path() string {\n\tif e.path.starts_with(e.root) {\n\t\treturn e.path[e.root.len + 1..]\n\t}\n\n\treturn e.path\n}\n\npub fn (e &EditorConfig) is_local() bool {\n\treturn e.path.starts_with(e.root)\n}\n"
  },
  {
    "path": "src/config/constants.v",
    "content": "module config\n\nimport os\nimport metadata\n\n// analyzer_name is the name of the analyzer.\npub const analyzer_name = 'v-analyzer'\n\n// analyzer_config_name is the name of the analyzer's configuration\npub const analyzer_config_name = 'config.toml'\n\n// analyzer_configs_path is the path to the directory containing the\n// root configuration files for the analyzer.\npub const analyzer_configs_path = os.join_path(os.home_dir(), '.config', 'v-analyzer')\n\n// analyzer_local_configs_folder_name is the name of the directory\n// containing the local configuration files for the analyzer.\npub const analyzer_local_configs_folder_name = '.v-analyzer'\n\n// analyzer_log_file_name is the name of the log file for the analyzer.\npub const analyzer_log_file_name = 'v-analyzer.log'\n\n// analyzer_logs_path is the path to the directory containing the\n// logs for the analyzer.\npub const analyzer_logs_path = os.join_path(analyzer_configs_path, 'logs')\n\n// analyzer_global_config_path is the path to the global configuration\n// file for the analyzer.\npub const analyzer_global_config_path = os.join_path(analyzer_configs_path, analyzer_config_name)\n\n// analyzer_caches_path is the path to the directory containing the\n// cache files for the analyzer.\npub const analyzer_caches_path = os.join_path(os.cache_dir(), 'v-analyzer',\n\t'${metadata.build_commit}_${os.file_last_mod_unix(os.executable())}')\n\n// analyzer_stubs_path is the path to the directory containing the\n// unpacked stub files for the analyzer.\npub const analyzer_stubs_path = os.join_path(analyzer_configs_path, 'metadata')\n\n// analyzer_stubs_version_path is the path to the file containing the version of the stubs.\npub const analyzer_stubs_version_path = os.join_path(analyzer_stubs_path, 'version.txt')\n\npub const default = '# Specifies the path to the V installation directory with `v` executable.\n# If not set, the plugin will try to find it on its own.\n# Set it if you get errors like \"Cannot find V standard library!\".\n#custom_vroot = \"~/v\"\n\n# Specifies the path where to store the cache.\n# By default, it is stored in the system\\'s cache directory.\n# You can set it to `./` to store the cache in the project\\'s directory, this is useful\n# if you want to debug the analyzer.\n# Basically, you don\\'t need to set it.\n#custom_cache_dir = \"./\"\n\n# Specifies whenever to enable semantic tokens or not.\n# - `full` — enables all semantic tokens. In this mode analyzer resolves all symbols\n#    in the file to provide the most accurate highlighting.\n# - `syntax` — enables only syntax tokens, such tokens highlight structural elements\n#    such as field names or import names.\n#    The fastest option, which is always enabled when the file contains more than 1000 lines.\n# - `none` — disables semantic tokens.\n# By default, `full` for files with less than 1000 lines, `syntax` for files with more.\nenable_semantic_tokens = \"full\"\n\n# Specifies inlay hints to show.\n[inlay_hints]\n# Specifies whenever to enable inlay hints or not.\n# By default, they are enabled.\nenable = true\n\n# Specifies whenever to show type hints for ranges or not.\n# Example:\n# ```\n# 0 ≤ .. < 10\n#   ^    ^\n# ```\n# or:\n# ```\n# a[0 ≤ .. < 10]\n#     ^    ^\n# ```\nenable_range_hints = true\n\n# Specifies whenever to show type hints for variables or not.\n# Example:\n# ```\n# name : Foo := foo()\n#      ^^^^^\n# ```\nenable_type_hints = true\n\n# Specifies whenever to show hints for implicit err variables or not.\n# Example:\n# ```\n# foo() or { err ->\n#            ^^^^^^\n# }\n# ```\nenable_implicit_err_hints = true\n\n# Specifies whenever to show hints for function parameters in call or not.\n# Example:\n# ```\n# fn foo(a int, b int) int {}\n#\n# foo(a: 1, b: 2)\n#     ^^    ^^\nenable_parameter_name_hints = true\n\n# Specifies whenever to show type hints for constants or not.\n# Example:\n# ```\n# const foo : int = 1\n#           ^^^^^\n# ```\nenable_constant_type_hints = true\n\n# Specifies whenever to show hints for enum field values or not.\n# Example:\n# ```\n# enum Foo {\n#   bar = 0\n#       ^^^\n#   baz = 1\n#       ^^^\n# }\n# ```\nenable_enum_field_value_hints = true\n\n# Specifies code lenses to show.\n[code_lens]\n# Specifies whenever to enable code lenses or not.\n# By default, they are enabled.\nenable = true\n\n# Specifies whenever to show code lenses for main function to run current directory or not.\n# Example:\n# ```\n# ▶ Run\n# fn main() {}\n# ```\nenable_run_lens = true\n\n# Specifies whenever to show code lenses for interface inheritors or not.\n# Example:\n# ```\n# 2 implementations\n# interface Foo {}\n# ```\nenable_inheritors_lens = true\n\n# Specifies whenever to show code lenses for structs implementing interfaces or not.\n# Example:\n# ```\n# implemented 2 interfaces\n# struct Boo {}\n# ```\nenable_super_interfaces_lens = true\n\n# Specifies whenever to show code lenses for test functions to run test or whole file or not.\n# Example:\n# ```\n# ▶ Run test | all file tests\n# fn test_foo() {}\n# ```\n# Note: \"all file tests\" is shown only for the first test function in the file.\nenable_run_tests_lens = true\n'\n"
  },
  {
    "path": "src/init.v",
    "content": "module main\n\nimport cli\nimport os\nimport config\nimport readline\nimport term\n\nfn init_cmd(cmd cli.Command) ! {\n\tpwd := os.getwd()\n\tif pwd == '' {\n\t\treturn error('Cannot get current working directory')\n\t}\n\n\tdirectory_for_config := os.join_path(pwd, config.analyzer_local_configs_folder_name)\n\tif !os.exists(directory_for_config) {\n\t\tos.mkdir_all(directory_for_config) or {\n\t\t\treturn error(\"Cannot create '${directory_for_config}' directory for config: ${err}\")\n\t\t}\n\n\t\tprintln(\"${term.green('✓')} Created '${config.analyzer_local_configs_folder_name}' directory for config\")\n\t}\n\n\tconfig_file := os.join_path(directory_for_config, config.analyzer_config_name)\n\tif os.exists(config_file) {\n\t\twarnln(\"Config file '${config_file}' already exists\")\n\t\tread_line := readline.read_line('Want to overwrite it? [y/N] ') or {\n\t\t\terrorln('Cannot read line: ${err}')\n\t\t\t'N'\n\t\t}\n\t\toverwrite := read_line.trim_space() == 'y'\n\t\tif !overwrite {\n\t\t\treturn\n\t\t}\n\t}\n\n\tos.write_file(config_file, config.default) or {\n\t\treturn error(\"Cannot write config file '${config_file}': ${err}\")\n\t}\n\n\tprintln(\"${term.green('✓')} Successfully created config file '${config_file}'\")\n}\n"
  },
  {
    "path": "src/jsonrpc/README.md",
    "content": "# Description\n\n`jsonrpc` module describes the JSON-RPC 2.0 implementation.\n"
  },
  {
    "path": "src/jsonrpc/jsonrpc.v",
    "content": "// Copyright (c) 2022 Ned Palacios. All rights reserved.\n// Use of this source code is governed by an MIT license\n// that can be found in the LICENSE file.\nmodule jsonrpc\n\nimport json\nimport strings\nimport io\n\npub const version = '2.0'\n\n// see\n// - https://www.jsonrpc.org/specification#error_object\n// - http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php\n// Invalid JSON was received by the server.\n// An error occurred on the server while parsing the JSON text.\npub const parse_error = error_with_code('Invalid JSON.', -32700)\n// The JSON sent is not a valid Request object.\npub const invalid_request = error_with_code('Invalid request.', -32600)\n// The method does not exist / is not available.\npub const method_not_found = error_with_code('Method not found.', -32601)\n// Invalid method parameter(s).\npub const invalid_params = error_with_code('Invalid params', -32602)\n// Internal JSON-RPC error.\npub const internal_error = error_with_code('Internal error.', -32693)\n// Server errors.\npub const server_error_start = error_with_code('Error occurred when starting server.', -32099)\npub const server_not_initialized = error_with_code('Server not initialized.', -32002)\npub const unknown_error = error_with_code('Unknown error.', -32001)\npub const server_error_end = error_with_code('Error occurred when stopping the server.', -32000)\npub const error_codes = [\n\tparse_error.code(),\n\tinvalid_request.code(),\n\tmethod_not_found.code(),\n\tinvalid_params.code(),\n\tinternal_error.code(),\n\tserver_error_start.code(),\n\tserver_not_initialized.code(),\n\tserver_error_end.code(),\n\tunknown_error.code(),\n]\n\n// Null represents the null value in JSON.\npub struct Null {}\n\npub const null = Null{}\n\n// Request is a representation of a rpc call to the server.\n// https://www.jsonrpc.org/specification#request_object\npub struct Request {\npub mut:\n\tjsonrpc string = version\n\tid      string @[raw]\n\tmethod  string\n\tparams  string @[raw]\n}\n\n// json returns the JSON string form of the Request.\npub fn (req Request) json() string {\n\t// NOTE: make request act as a notification for server_test_utils\n\tid_payload := if req.id.len != 0 { ',\"id\":${req.id},' } else { ',' }\n\treturn '{\"jsonrpc\":\"${version}\"${id_payload}\"method\":\"${req.method}\",\"params\":${req.params}}'\n}\n\n// decode_params decodes the parameters of a Request.\npub fn (req Request) decode_params[T]() !T {\n\treturn json.decode(T, req.params) or { return err }\n}\n\n// Response is a representation of server reply after an rpc call was made.\n// https://www.jsonrpc.org/specification#response_object\npub struct Response[T] {\npub:\n\tjsonrpc string = version\n\tid      string\n\t//\terror   ResponseError\n\tresult T\n\terror  ResponseError\n}\n\n// json returns the JSON string form of the Response<T>\npub fn (resp Response[T]) json() string {\n\tmut resp_wr := strings.new_builder(100)\n\tdefer {\n\t\tunsafe { resp_wr.free() }\n\t}\n\tencode_response[T](resp, mut resp_wr)\n\treturn resp_wr.str()\n}\n\nconst null_in_u8 = 'null'.bytes()\n\nconst error_field_in_u8 = ',\"error\":'.bytes()\n\nconst result_field_in_u8 = ',\"result\":'.bytes()\n\nfn encode_response[T](resp Response[T], mut writer io.Writer) {\n\twriter.write('{\"jsonrpc\":\"${version}\",\"id\":'.bytes()) or {}\n\tif resp.id.len == 0 {\n\t\twriter.write(null_in_u8) or {}\n\t} else {\n\t\twriter.write(resp.id.bytes()) or {}\n\t}\n\tif resp.error.code != 0 {\n\t\terr := json.encode(resp.error)\n\t\twriter.write(error_field_in_u8) or {}\n\t\twriter.write(err.bytes()) or {}\n\t} else {\n\t\twriter.write(result_field_in_u8) or {}\n\t\t$if T is Null {\n\t\t\twriter.write(null_in_u8) or {}\n\t\t} $else {\n\t\t\tres := json.encode(resp.result)\n\t\t\twriter.write(res.bytes()) or {}\n\t\t}\n\t}\n\twriter.write([u8(`}`)]) or {}\n}\n\n// NotificationMessage is a Request object without the ID. A Request object that is a\n// Notification signifies the Client's lack of interest in the corresponding Response object,\n// and as such no Response object needs to be returned to the client. The Server MUST NOT reply\n// to a Notification, including those that are within a batch request.\n//\n// Notifications are not confirmable by definition, since they do not have a Response object to be\n// returned. As such, the Client would not be aware of any errors (like e.g. \"Invalid params\",\"Internal error\").\n// https://www.jsonrpc.org/specification#notification\npub struct NotificationMessage[T] {\npub:\n\tjsonrpc string = version\n\tmethod  string\n\tparams  T\n}\n\n// json returns the JSON string form of the NotificationMessage.\npub fn (notif NotificationMessage[T]) json() string {\n\tmut notif_wr := strings.new_builder(100)\n\tdefer {\n\t\tunsafe { notif_wr.free() }\n\t}\n\tencode_notification[T](notif, mut notif_wr)\n\treturn notif_wr.str()\n}\n\nfn encode_notification[T](notif NotificationMessage[T], mut writer io.Writer) {\n\twriter.write('{\"jsonrpc\":\"${version}\",\"method\":\"${notif.method}\",\"params\":'.bytes()) or {}\n\t$if T is Null {\n\t\twriter.write(null_in_u8) or {}\n\t} $else {\n\t\tres := json.encode(notif.params)\n\t\twriter.write(res.bytes()) or {}\n\t}\n\twriter.write([u8(`}`)]) or {}\n}\n\nfn encode_request[T](notif NotificationMessage[T], mut writer io.Writer) {\n\twriter.write('{\"jsonrpc\":\"${version}\",\"id\": 1, \"method\":\"${notif.method}\",\"params\":'.bytes()) or {}\n\t$if T is Null {\n\t\twriter.write(null_in_u8) or {}\n\t} $else {\n\t\tres := json.encode(notif.params)\n\t\twriter.write(res.bytes()) or {}\n\t}\n\twriter.write([u8(`}`)]) or {}\n}\n\n// ResponseError is a representation of an error when a rpc call encounters an error.\n// When a rpc call encounters an error, the Response Object MUST contain the error member\n// with a value that is a Object with the following members:\n// https://www.jsonrpc.org/specification#error_object\npub struct ResponseError {\npub mut:\n\tcode    int\n\tmessage string\n\tdata    string\n}\n\npub fn (err ResponseError) code() int {\n\treturn err.code\n}\n\npub fn (err ResponseError) msg() string {\n\treturn err.message\n}\n\n// err returns the ResponseError as an implementation of IError.\npub fn (e ResponseError) err() IError {\n\treturn IError(e)\n}\n\n@[params]\npub struct ResponseErrorGeneratorParams {\npub:\n\terror IError @[required]\n\tdata  string\n}\n\n// response_error creates a ResponseError from the given IError.\n@[inline]\npub fn response_error(params ResponseErrorGeneratorParams) ResponseError {\n\treturn ResponseError{\n\t\tcode:    params.error.code()\n\t\tmessage: params.error.msg()\n\t\tdata:    params.data\n\t}\n}\n"
  },
  {
    "path": "src/jsonrpc/jsonrpc_test.v",
    "content": "import jsonrpc\n\nfn test_response_json_null() {\n\tresp := jsonrpc.Response[jsonrpc.Null]{\n\t\tid: '1'\n\t}\n\tassert resp.json() == '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":null}'\n}\n\nfn test_notification_json_null() {\n\tresp := jsonrpc.NotificationMessage[jsonrpc.Null]{\n\t\tmethod: 'test'\n\t}\n\tassert resp.json() == '{\"jsonrpc\":\"2.0\",\"method\":\"test\",\"params\":null}'\n}\n"
  },
  {
    "path": "src/jsonrpc/server.v",
    "content": "// Copyright (c) 2022 Ned Palacios. All rights reserved.\n// Use of this source code is governed by an MIT license\n// that can be found in the LICENSE file.\nmodule jsonrpc\n\nimport io\nimport json\nimport sync\nimport strings\n\n// Server represents a JSONRPC server that sends/receives data\n// from a stream (an io.ReaderWriter), inspects data with interceptors\n// and hands over the decoded request to a Handler.\n@[heap]\npub struct Server {\nmut:\n\treq_buf    strings.Builder = strings.new_builder(4096)\n\tconlen_buf strings.Builder = strings.new_builder(4096)\n\tres_buf    strings.Builder = strings.new_builder(4096)\npub mut:\n\tstream       io.ReaderWriter\n\tinterceptors []Interceptor\n\thandler      Handler\n}\n\n// intercept_raw_request intercepts the incoming raw request buffer\n// to the interceptors.\npub fn (mut s Server) intercept_raw_request(req []u8) ! {\n\tfor mut interceptor in s.interceptors {\n\t\tinterceptor.on_raw_request(req)!\n\t}\n}\n\n// intercept_request intercepts the incoming decoded JSONRPC Request\n// to the interceptors.\npub fn (mut s Server) intercept_request(req &Request) ! {\n\tfor mut interceptor in s.interceptors {\n\t\tinterceptor.on_request(req)!\n\t}\n}\n\n// intercept_encoded_response intercepts the outgoing raw response buffer\n// to the interceptors.\npub fn (mut s Server) intercept_encoded_response(resp []u8) {\n\tfor mut interceptor in s.interceptors {\n\t\tinterceptor.on_encoded_response(resp)\n\t}\n}\n\npub interface InterceptorData {}\n\n// dispatch_event sends a custom event to the interceptors.\npub fn (mut s Server) dispatch_event(event_name string, data InterceptorData) ! {\n\tfor mut i in s.interceptors {\n\t\ti.on_event(event_name, data)!\n\t}\n}\n\n// process_raw_request decodes the raw request string into JSONRPC request.\nfn (_ Server) process_raw_request(raw_request string) !Request {\n\tjson_payload := raw_request.all_after('\\r\\n\\r\\n')\n\treturn json.decode(Request, json_payload) or { return err }\n}\n\n// respond executes the incoming request into a response.\n// for testing purposes only.\npub fn (mut s Server) respond() ! {\n\tmut base_rw := s.writer()\n\treturn s.internal_respond(mut base_rw)\n}\n\nfn (mut s Server) internal_respond(mut base_rw ResponseWriter) ! {\n\tdefer {\n\t\ts.req_buf.go_back_to(0)\n\t}\n\ts.stream.read(mut s.req_buf) or {\n\t\tif err is io.Eof {\n\t\t\treturn err\n\t\t}\n\t\treturn err\n\t}\n\n\treq := s.process_raw_request(s.req_buf.after(0)) or {\n\t\tbase_rw.write_error(response_error(error: parse_error))\n\t\treturn err\n\t}\n\n\ts.intercept_request(&req) or {\n\t\tbase_rw.write_error(response_error(error: err))\n\t\treturn err\n\t}\n\n\tmut rw := ResponseWriter{\n\t\tserver: s\n\t\twriter: base_rw.writer\n\t\tsb:     base_rw.sb\n\t\treq_id: req.id\n\t}\n\n\ts.handler.handle_jsonrpc(&req, mut rw) or {\n\t\t// do not send response error if request is a notification\n\t\tif req.id.len != 0 {\n\t\t\tif err is none {\n\t\t\t\trw.write(null)\n\t\t\t} else if err is ResponseError {\n\t\t\t\trw.write_error(err)\n\t\t\t} else if err.code() !in error_codes {\n\t\t\t\trw.write_error(response_error(error: unknown_error))\n\t\t\t} else {\n\t\t\t\trw.write_error(response_error(error: err))\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n}\n\n@[params]\npub struct NewWriterConfig {\npub:\n\town_buffer bool\n}\n\n// writer returns the Server's current ResponseWriter\npub fn (s &Server) writer(cfg NewWriterConfig) &ResponseWriter {\n\treturn &ResponseWriter{\n\t\tserver: s\n\t\twriter: io.MultiWriter{\n\t\t\twriters: [\n\t\t\t\tInterceptorWriter{\n\t\t\t\t\tinterceptors: s.interceptors\n\t\t\t\t},\n\t\t\t\t// NOTE: writing content lengths should be an interceptor\n\t\t\t\t// since there are some situations that a payload is only\n\t\t\t\t// passthrough between processes and does not need a\n\t\t\t\t// \"repackaging\" of the outgoing data\n\t\t\t\tWriter{\n\t\t\t\t\tclen_sb:     if cfg.own_buffer { s.conlen_buf.clone() } else { s.conlen_buf }\n\t\t\t\t\tread_writer: s.stream\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\t\tsb:     if cfg.own_buffer { s.res_buf.clone() } else { s.res_buf }\n\t}\n}\n\n// start executes a loop and observes the incoming request from the stream.\npub fn (mut s Server) start() {\n\tmut rw := s.writer()\n\tfor {\n\t\ts.internal_respond(mut rw) or {\n\t\t\tif err is io.Eof {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t}\n}\n\n// Interceptor is an interface that observes and inspects the data\n// before handing over to the Handler.\npub interface Interceptor {\nmut:\n\ton_event(name string, data InterceptorData) !\n\ton_raw_request(req []u8) !\n\ton_request(req &Request) !\n\ton_encoded_response(resp []u8) // we cant use generic methods without marking the interface as generic\n}\n\n// Handler is an interface that handles the JSONRPC request and\n// returns a response data via a ResponseWriter.\npub interface Handler {\nmut:\n\thandle_jsonrpc(req &Request, mut wr ResponseWriter) !\n}\n\n// ResponseWriter constructs and sends a JSONRPC response to the stream.\npub struct ResponseWriter {\nmut:\n\tmutex sync.Mutex\n\tsb    strings.Builder\npub mut:\n\treq_id string  = 'null' // raw JSON\n\tserver &Server = unsafe { nil }\n\twriter io.Writer\n}\n\nfn (mut rw ResponseWriter) flush() {\n\trw.writer.write(rw.sb) or {}\n\trw.sb.go_back_to(0)\n}\n\n// write sends the given payload to the stream.\npub fn (mut rw ResponseWriter) write[T](payload T) {\n\trw.mutex.@lock()\n\tdefer {\n\t\trw.mutex.unlock()\n\t}\n\n\tfinal_resp := Response[T]{\n\t\tid:     rw.req_id\n\t\tresult: payload\n\t}\n\tencode_response[T](final_resp, mut rw.sb)\n\trw.flush()\n}\n\npub fn (mut rw ResponseWriter) write_empty() {\n\trw.write[Null](null)\n}\n\n// write_notify sends the given method and params as\n// a server notification to the stream.\npub fn (mut rw ResponseWriter) write_notify[T](method string, params T) {\n\trw.mutex.@lock()\n\tdefer {\n\t\trw.mutex.unlock()\n\t}\n\n\tnotif := NotificationMessage[T]{\n\t\tmethod: method\n\t\tparams: params\n\t}\n\tencode_notification[T](notif, mut rw.sb)\n\trw.flush()\n}\n\npub fn (mut rw ResponseWriter) write_request[T](method string, params T) {\n\trw.mutex.@lock()\n\tdefer {\n\t\trw.mutex.unlock()\n\t}\n\n\tnotif := NotificationMessage[T]{\n\t\tmethod: method\n\t\tparams: params\n\t}\n\tencode_request[T](notif, mut rw.sb)\n\trw.flush()\n}\n\n// write_error sends a ResponseError to the stream.\npub fn (mut rw ResponseWriter) write_error(err &ResponseError) {\n\trw.mutex.@lock()\n\tdefer {\n\t\trw.mutex.unlock()\n\t}\n\n\tfinal_resp := Response[string]{\n\t\tid:    rw.req_id\n\t\terror: err\n\t}\n\tencode_response[string](final_resp, mut rw.sb)\n\trw.flush()\n}\n\n// Writer is an internal representation of a raw response writer.\n// It adds a Content-Length header to the response before handing\n// over to the io.ReaderWriter.\nstruct Writer {\nmut:\n\tclen_sb     strings.Builder\n\tread_writer io.ReaderWriter\n}\n\nfn (mut w Writer) write(byt []u8) !int {\n\tdefer {\n\t\tw.clen_sb.go_back_to(0)\n\t}\n\tw.clen_sb.write_string('Content-Length: ${byt.len}\\r\\n\\r\\n')\n\tw.clen_sb.write(byt) or {}\n\treturn w.read_writer.write(w.clen_sb)\n}\n\nstruct InterceptorWriter {\nmut:\n\tinterceptors []Interceptor\n}\n\nfn (mut wr InterceptorWriter) write(buf []u8) !int {\n\tfor mut interceptor in wr.interceptors {\n\t\tinterceptor.on_encoded_response(buf)\n\t}\n\treturn buf.len\n}\n\n// PassiveHandler is an implementation of a Handler\n// used as a default value for Server.handler\npub struct PassiveHandler {}\n\nfn (mut _ PassiveHandler) handle_jsonrpc(req &Request, mut rw ResponseWriter) ! {}\n\n// is_interceptor_enabled checks if the given T is enabled in a Server.\npub fn is_interceptor_enabled[T](server &Server) bool {\n\tget_interceptor[T](server) or { return false }\n\treturn true\n}\n\npub fn get_interceptor[T](server &Server) ?&T {\n\tfor inter in server.interceptors {\n\t\tif inter is T {\n\t\t\treturn inter\n\t\t}\n\t}\n\treturn none\n}\n"
  },
  {
    "path": "src/jsonrpc/server_test.v",
    "content": "import io\nimport jsonrpc\nimport jsonrpc.server_test_utils { RpcResult, TestClient, TestStream }\n\nstruct TestHandler {}\n\nstruct SumParams {\nmut:\n\tnums []int\n}\n\nfn (mut _ TestHandler) handle_jsonrpc(req &jsonrpc.Request, mut wr jsonrpc.ResponseWriter) ! {\n\tmatch req.method {\n\t\t'sum' {\n\t\t\tparams := req.decode_params[SumParams]()!\n\n\t\t\tmut res := 0\n\t\t\tfor n in params.nums {\n\t\t\t\tres += n\n\t\t\t}\n\n\t\t\twr.write(RpcResult[int]{ result: res })\n\t\t}\n\t\t'mirror' {\n\t\t\ttexts := req.decode_params[[]string]()!\n\t\t\tif texts.len == 0 || texts[0] == '0' {\n\t\t\t\twr.write(jsonrpc.null)\n\t\t\t\treturn\n\t\t\t}\n\t\t\twr.write(RpcResult[string]{texts[0]})\n\t\t}\n\t\t'hello' {\n\t\t\twr.write(RpcResult[string]{'Hello world!'})\n\t\t}\n\t\t'trigger' {\n\t\t\twr.server.dispatch_event('record', 'dispatched!')!\n\t\t\twr.write(RpcResult[string]{'triggered'})\n\t\t}\n\t\telse {\n\t\t\treturn jsonrpc.response_error(error: jsonrpc.method_not_found).err()\n\t\t}\n\t}\n}\n\nfn test_server() {\n\tmut stream := &TestStream{}\n\tmut server := &jsonrpc.Server{\n\t\thandler: &TestHandler{}\n\t\tstream:  stream\n\t}\n\n\tmut client := TestClient{\n\t\tserver: server\n\t\tstream: stream\n\t}\n\n\tsum_result := client.send[SumParams, RpcResult[int]]('sum', SumParams{ nums: [1, 2, 4] })!\n\n\tassert sum_result.result == 7\n\n\thello_result := client.send[string, RpcResult[string]]('hello', '')!\n\n\tassert hello_result.result == 'Hello world!'\n\n\tclient.send[string, RpcResult[int]]('multiply', 'test') or {\n\t\tif err !is io.Eof {\n\t\t\tassert err.msg() == 'Method not found.'\n\t\t}\n\t}\n\n\tclient.send[[]string, RpcResult[string]]('mirror', ['0']) or { assert err is io.Eof }\n}\n\nstruct TestInterceptor {\nmut:\n\tmethods_recv []string\n\tmessages     []string\n}\n\nfn (mut t TestInterceptor) on_event(name string, data jsonrpc.InterceptorData) ! {\n\tif name == 'record' && data is string {\n\t\tt.messages << data\n\t}\n}\n\nfn (mut _ TestInterceptor) on_raw_request(req []u8) ! {}\n\nfn (mut t TestInterceptor) on_request(req &jsonrpc.Request) ! {\n\tt.methods_recv << req.method\n}\n\nfn (mut t TestInterceptor) on_encoded_response(resp []u8) {\n\tt.messages << 'test!'\n}\n\nfn test_interceptor() {\n\tmut test_inter := &TestInterceptor{}\n\tmut stream := &TestStream{}\n\n\tmut server := &jsonrpc.Server{\n\t\thandler:      &TestHandler{}\n\t\tinterceptors: [test_inter]\n\t\tstream:       stream\n\t}\n\n\tmut client := TestClient{\n\t\tserver: server\n\t\tstream: stream\n\t}\n\n\tclient.send[SumParams, RpcResult[int]]('sum', SumParams{ nums: [1, 2, 4] })!\n\n\tassert test_inter.methods_recv.len == 1\n\tassert test_inter.methods_recv[0] == 'sum'\n\tassert test_inter.messages.len == 1\n\n\tclient.send[string, RpcResult[string]]('trigger', '')!\n\n\tassert test_inter.methods_recv.len == 2\n\tassert test_inter.methods_recv[1] == 'trigger'\n\tassert test_inter.messages.len == 3\n\tassert test_inter.messages[1] == 'dispatched!'\n}\n"
  },
  {
    "path": "src/jsonrpc/server_test_utils/server_test_utils.v",
    "content": "// Copyright (c) 2022 Ned Palacios. All rights reserved.\n// Use of this source code is governed by an MIT license\n// that can be found in the LICENSE file.\nmodule server_test_utils\n\nimport io\nimport jsonrpc\nimport json\nimport datatypes\n\n// new_test_client creates a test client to be used for observing responses\n// and notifications from the given handler and interceptors\npub fn new_test_client(handler jsonrpc.Handler, interceptors ...jsonrpc.Interceptor) &TestClient {\n\tmut stream := &TestStream{}\n\tmut server := &jsonrpc.Server{\n\t\thandler:      handler\n\t\tinterceptors: interceptors\n\t\tstream:       stream\n\t}\n\n\treturn &TestClient{\n\t\tserver: server\n\t\tstream: stream\n\t}\n}\n\n// TestResponse is a version of jsonrpc.Response<T> that decodes\n// incoming JSON as raw JSON string.\nstruct TestResponse {\n\traw_id     string @[json: id; raw]\n\traw_result string @[json: result; raw]\n}\n\n// TestClient is a JSONRPC Client used for simulating communication between client and\n// JSONRPC server. This exposes the JSONRPC server and a test stream for sending data\n// as a server or as a client\npub struct TestClient {\nmut:\n\tid int\npub mut:\n\tserver &jsonrpc.Server\n\tstream &TestStream\n}\n\n// send sends a request and receives a decoded response result.\npub fn (mut tc TestClient) send[T, U](method string, params T) !U {\n\tparams_json := json.encode(params)\n\treq := jsonrpc.Request{\n\t\tid:     '${tc.id}'\n\t\tmethod: method\n\t\tparams: params_json\n\t}\n\n\ttc.stream.send(req)\n\ttc.server.respond() or { return err }\n\traw_json_content := tc.stream.response_text(req.id)\n\tif raw_json_content.len == 0 || raw_json_content == 'null' {\n\t\treturn IError(io.Eof{})\n\t}\n\tprintln(raw_json_content)\n\treturn json.decode(U, raw_json_content)!\n}\n\n// notify is a version of send but instead of returning a response,\n// it only notifies the server. Effectively sending a request as a\n// notification.\npub fn (mut tc TestClient) notify[T](method string, params T) ! {\n\tparams_json := json.encode(params)\n\treq := jsonrpc.Request{\n\t\tid:     ''\n\t\tmethod: method\n\t\tparams: params_json\n\t}\n\n\ttc.stream.send(req)\n\ttc.server.respond()!\n}\n\n// TestStream is a io.ReadWriter-compliant stream for sending\n// and receiving responses from between the client and the server.\n// Aside from being a ReaderWriter, it exposes additional methods\n// for decoding JSONRPC response and notifications.\npub struct TestStream {\nmut:\n\tnotif_idx int\n\tnotif_buf [][]u8 = [][]u8{len: 20, cap: 20}\n\tresp_buf  map[string]TestResponse\n\treq_buf   datatypes.Queue[[]u8]\n}\n\n// read receives the incoming request buffer.\npub fn (mut rw TestStream) read(mut buf []u8) !int {\n\treq := rw.req_buf.pop() or { return IError(io.Eof{}) }\n\tbuf << req\n\treturn req.len\n}\n\n// write receives the outgoing response/notification buffer.\npub fn (mut rw TestStream) write(buf []u8) !int {\n\traw_json_content := buf.bytestr().all_after('\\r\\n\\r\\n')\n\tif raw_json_content.contains('\"result\":') {\n\t\tresp := json.decode(TestResponse, raw_json_content) or { return err }\n\t\trw.resp_buf[resp.raw_id] = resp\n\t} else if raw_json_content.contains('\"params\":') {\n\t\tidx := rw.notif_idx % 20\n\t\tfor i := idx + 1; i < rw.notif_buf.len; i++ {\n\t\t\tif rw.notif_buf[i].len != 0 {\n\t\t\t\trw.notif_buf[idx].clear()\n\t\t\t}\n\t\t}\n\t\trw.notif_buf[idx] << buf\n\t\trw.notif_idx++\n\t} else {\n\t\treturn error('none')\n\t}\n\treturn buf.len\n}\n\n// send stringifies and dispatches the jsonrpc.Request into the request queue.\npub fn (mut rw TestStream) send(req jsonrpc.Request) {\n\treq_json := req.json()\n\trw.req_buf.push('Content-Length: ${req_json.len}\\r\\n\\r\\n${req_json}'.bytes())\n}\n\n// response_text returns the raw response result of the given request id.\npub fn (rw &TestStream) response_text(raw_id string) string {\n\treturn rw.resp_buf[raw_id].raw_result\n}\n\n// notification_at returns the jsonrpc.Notification<T> in a given index.\npub fn (rw &TestStream) notification_at[T](idx int) !jsonrpc.NotificationMessage[T] {\n\traw_json_content := rw.notif_buf[idx].bytestr().all_after('\\r\\n\\r\\n')\n\treturn json.decode(jsonrpc.NotificationMessage[T], raw_json_content)!\n}\n\n// last_notification_at_method returns the last jsonrpc.Notification<T> from the given method name.\npub fn (rw &TestStream) last_notification_at_method[T](method_name string) !jsonrpc.NotificationMessage[T] {\n\tfor i := rw.notif_buf.len - 1; i >= 0; i-- {\n\t\traw_notif_content := rw.notif_buf[i]\n\t\tif raw_notif_content.len == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif raw_notif_content.bytestr().contains('\"method\":\"${method_name}\"') {\n\t\t\treturn rw.notification_at[T](i) or { return err }\n\t\t}\n\t}\n\treturn error('')\n}\n\n// RpcResult<T> is a result form used for primitive types.\npub struct RpcResult[T] {\npub mut:\n\tresult T\n}\n"
  },
  {
    "path": "src/loglib/ColorMode.v",
    "content": "module loglib\n\npub enum ColorMode {\n\tauto\n\talways\n\tnever\n}\n\nfn get_color_mode_by_name(name string) ?ColorMode {\n\treturn match name {\n\t\t'auto' { ColorMode.auto }\n\t\t'always' { ColorMode.always }\n\t\t'never' { ColorMode.never }\n\t\telse { none }\n\t}\n}\n"
  },
  {
    "path": "src/loglib/Entry.v",
    "content": "module loglib\n\nimport time\nimport os\n\npub type Fields = map[string]string\n\npub struct Entry {\npub mut:\n\tlogger  &Logger\n\tfields  Fields\n\ttime    time.Time\n\tlevel   LogLevel\n\tmessage string\n}\n\npub fn new_entry(logger &Logger) &Entry {\n\treturn &Entry{\n\t\tlogger: logger\n\t}\n}\n\npub fn (entry &Entry) clone() &Entry {\n\treturn &Entry{\n\t\tlogger:  entry.logger\n\t\tfields:  entry.fields.clone()\n\t\ttime:    entry.time\n\t\tlevel:   entry.level\n\t\tmessage: entry.message\n\t}\n}\n\npub fn (entry &Entry) with_fields(fields Fields) &Entry {\n\tmut own_fields := entry.fields.clone()\n\tfor k, v in fields {\n\t\town_fields[k] = v\n\t}\n\n\treturn &Entry{\n\t\tlogger:  entry.logger\n\t\tfields:  own_fields\n\t\ttime:    entry.time\n\t\tlevel:   entry.level\n\t\tmessage: entry.message\n\t}\n}\n\npub fn (entry &Entry) with_duration(dur time.Duration) &Entry {\n\treturn entry.with_fields({\n\t\t'duration': dur.str()\n\t})\n}\n\npub fn (entry &Entry) with_gc_heap_usage(usage GCHeapUsage) &Entry {\n\treturn entry.with_fields({\n\t\t'heap_size':      usage.heap_size.str()\n\t\t'free_bytes':     usage.free_bytes.str()\n\t\t'total_bytes':    usage.total_bytes.str()\n\t\t'unmapped_bytes': usage.unmapped_bytes.str()\n\t\t'bytes_since_gc': usage.bytes_since_gc.str()\n\t})\n}\n\npub fn (entry &Entry) error(msg ...string) {\n\tentry.log(.error, ...msg)\n}\n\npub fn (entry &Entry) warn(msg ...string) {\n\tentry.log(.warn, ...msg)\n}\n\npub fn (entry &Entry) info(msg ...string) {\n\tentry.log(.info, ...msg)\n}\n\npub fn (entry &Entry) trace(msg ...string) {\n\tentry.log(.trace, ...msg)\n}\n\npub fn (entry &Entry) log(level LogLevel, msg ...string) {\n\tif !entry.logger.is_level_enabled(level) {\n\t\treturn\n\t}\n\tentry.log_impl(level, ...msg)\n}\n\npub fn (entry &Entry) log_one(level LogLevel, msg string) {\n\tentry.log(level, msg)\n}\n\npub fn (entry &Entry) log_impl(level LogLevel, msg ...string) {\n\tmut new_entry := entry.clone()\n\tnew_entry.time = time.now()\n\tnew_entry.level = level\n\tnew_entry.message = msg.join(' ')\n\n\tnew_entry.write()\n\n\tif u64(level) <= u64(LogLevel.panic) {\n\t\tpanic(new_entry)\n\t}\n}\n\nfn (mut entry Entry) write() {\n\tformatted := entry.logger.formatter.format(entry) or {\n\t\teprintln('failed to format log message: ${err}')\n\t\treturn\n\t}\n\n\tentry.logger.out.write(formatted) or {\n\t\teprintln('failed to write log message: ${err}')\n\t\treturn\n\t}\n\n\tif time.since(entry.logger.last_flush) > entry.logger.flush_rate {\n\t\tmut out := entry.logger.out\n\t\tif mut out is os.File {\n\t\t\tout.flush()\n\t\t}\n\n\t\tentry.logger.last_flush = time.now()\n\t}\n}\n"
  },
  {
    "path": "src/loglib/Formatter.v",
    "content": "module loglib\n\npub interface Formatter {\nmut:\n\tformat(entry &Entry) ![]u8\n}\n"
  },
  {
    "path": "src/loglib/LogLevel.v",
    "content": "module loglib\n\npub enum LogLevel {\n\tpanic\n\tfatal\n\terror\n\twarn\n\tinfo\n\tdebug\n\ttrace\n}\n\nfn (l LogLevel) label() string {\n\treturn match l {\n\t\t.panic { 'PANIC' }\n\t\t.fatal { 'FATAL' }\n\t\t.error { 'ERROR' }\n\t\t.warn { 'WARN' }\n\t\t.info { 'INFO' }\n\t\t.debug { 'DEBUG' }\n\t\t.trace { 'TRACE' }\n\t}\n}\n"
  },
  {
    "path": "src/loglib/Logger.v",
    "content": "@[translated]\nmodule loglib\n\nimport term\nimport io\nimport os\nimport time\n\n__global logger = Logger{\n\tformatter: TextFormatter{}\n\tout:       os.stderr()\n}\n\npub const support_colors = term.can_show_color_on_stderr() && term.can_show_color_on_stdout()\n\n@[heap]\npub struct Logger {\npub mut:\n\tdisabled   bool\n\tcolor_mode ColorMode\n\n\tformatter  Formatter\n\tout        io.Writer\n\tlast_flush time.Time\n\tflush_rate time.Duration = 5 * time.second\n\n\tlevel u64 = u64(LogLevel.info)\n}\n\n@[inline]\npub fn (mut l Logger) disable() {\n\tl.disabled = true\n}\n\n@[inline]\npub fn (mut l Logger) enable() {\n\tl.disabled = false\n}\n\n@[inline]\npub fn (mut l Logger) use_color_mode(mode ColorMode) {\n\tl.color_mode = mode\n}\n\n@[inline]\npub fn (mut l Logger) use_color_mode_string(mode string) {\n\tenum_value := get_color_mode_by_name(mode) or { .auto }\n\tl.color_mode = enum_value\n}\n\n@[inline]\npub fn (l &Logger) level() u64 {\n\treturn l.level\n}\n\n@[inline]\npub fn (mut l Logger) set_level(level LogLevel) {\n\tl.level = u64(level)\n}\n\n@[inline]\npub fn (mut l Logger) set_flush_rate(dur time.Duration) {\n\tl.flush_rate = dur\n}\n\n@[inline]\npub fn (mut l Logger) set_output(out io.Writer) {\n\tl.out = out\n}\n\n@[inline]\npub fn (mut l Logger) get_output() io.Writer {\n\treturn l.out\n}\n\n@[inline]\npub fn (l &Logger) is_level_enabled(level LogLevel) bool {\n\treturn l.level() >= u64(level)\n}\n\npub fn (l &Logger) log(level LogLevel, msg ...string) {\n\tif !l.is_level_enabled(level) {\n\t\treturn\n\t}\n\n\tentry := new_entry(l)\n\tentry.log(level, ...msg)\n}\n\n@[inline]\npub fn (mut l Logger) with_fields(fields Fields) &Entry {\n\tentry := new_entry(l)\n\treturn entry.with_fields(fields)\n}\n\n@[inline]\npub fn (mut l Logger) with_duration(dur time.Duration) &Entry {\n\tentry := new_entry(l)\n\treturn entry.with_duration(dur)\n}\n\n@[inline]\npub fn (mut l Logger) with_gc_heap_usage(usage GCHeapUsage) &Entry {\n\tentry := new_entry(l)\n\treturn entry.with_gc_heap_usage(usage)\n}\n"
  },
  {
    "path": "src/loglib/TextFormatter.v",
    "content": "module loglib\n\nimport strings\nimport term\n\npub struct TextFormatter {\nmut:\n\tis_terminal bool\n\tinitialized bool\n}\n\nfn (mut t TextFormatter) init(entry &Entry) {\n\tt.is_terminal = check_if_terminal(entry.logger.out)\n}\n\nfn (mut t TextFormatter) format(entry &Entry) ![]u8 {\n\tif !t.initialized {\n\t\tt.init(entry)\n\t\tt.initialized = true\n\t}\n\n\tmut sb := strings.new_builder(10)\n\n\tsb.write_string(t.colorize(entry, entry.time.format_ss(), term.gray))\n\tsb.write_string(' ')\n\tt.format_level(entry, mut sb)\n\tsb.write_string(' ')\n\tt.format_message(entry, mut sb)\n\tt.format_fields(entry, mut sb)\n\tsb.write_string('\\n')\n\n\treturn sb\n}\n\nfn (t &TextFormatter) format_level(entry &Entry, mut sb strings.Builder) {\n\tlevel := entry.level\n\tlevel_label := level.label()\n\tcolored := t.colorize(entry, '[${level_label}]', t.level_color(level))\n\tsb.write_string(colored)\n\n\tif level in [.info, .warn] {\n\t\tsb.write_string(' ')\n\t}\n}\n\nfn (t &TextFormatter) format_message(entry &Entry, mut sb strings.Builder) {\n\tmut message := entry.message\n\n\tif message.len < 35 && entry.fields.len != 0 {\n\t\tmessage = message + ' '.repeat(35 - message.len)\n\t}\n\n\tsb.write_string(message)\n}\n\nfn (t &TextFormatter) format_fields(entry &Entry, mut sb strings.Builder) {\n\tfields := entry.fields\n\tif fields.len == 0 {\n\t\treturn\n\t}\n\n\tlevel_color := t.level_color(entry.level)\n\tsb.write_string(' ')\n\n\tmut index := 0\n\tfor key, field in fields {\n\t\tsb.write_string(t.colorize(entry, key, level_color))\n\t\tsb.write_string('=')\n\t\tsb.write_string(field)\n\n\t\tif index <= fields.len - 1 {\n\t\t\tsb.write_string(' ')\n\t\t}\n\t\tindex++\n\t}\n}\n\nfn (t &TextFormatter) colorize(entry &Entry, msg string, fun fn (msg string) string) string {\n\tif !support_colors || entry.logger.color_mode == .never || !t.is_terminal {\n\t\treturn msg\n\t}\n\n\treturn fun(msg)\n}\n\n@[inline]\nfn (_ &TextFormatter) level_color(level LogLevel) fn (msg string) string {\n\treturn match level {\n\t\t.panic { term.red }\n\t\t.fatal { term.red }\n\t\t.error { term.red }\n\t\t.warn { term.yellow }\n\t\t.info { term.gray }\n\t\t.debug { term.gray }\n\t\t.trace { term.gray }\n\t}\n}\n"
  },
  {
    "path": "src/loglib/log.v",
    "content": "module loglib\n\nimport io\nimport time\n\n@[inline]\npub fn log(level LogLevel, msg ...string) {\n\tlogger.log(level, ...msg)\n}\n\n@[inline]\npub fn log_one(level LogLevel, msg string) {\n\tlogger.log(level, msg)\n}\n\n@[inline]\npub fn warn(msg ...string) {\n\tlogger.log(.warn, ...msg)\n}\n\n@[inline]\npub fn info(msg ...string) {\n\tlogger.log(.info, ...msg)\n}\n\n@[inline]\npub fn trace(msg ...string) {\n\tlogger.log(.trace, ...msg)\n}\n\n@[inline]\npub fn error(msg ...string) {\n\tlogger.log(.error, ...msg)\n}\n\n@[inline]\npub fn set_level(level LogLevel) {\n\tlogger.set_level(level)\n}\n\n@[inline]\npub fn set_flush_rate(dur time.Duration) {\n\tlogger.flush_rate = dur\n}\n\n@[inline]\npub fn set_output(out io.Writer) {\n\tlogger.set_output(out)\n}\n\n@[inline]\npub fn get_output() io.Writer {\n\treturn logger.get_output()\n}\n\n@[inline]\npub fn with_fields(fields Fields) &Entry {\n\treturn logger.with_fields(fields)\n}\n\n@[inline]\npub fn with_duration(dur time.Duration) &Entry {\n\treturn logger.with_duration(dur)\n}\n\n@[inline]\npub fn with_gc_heap_usage(usage GCHeapUsage) &Entry {\n\treturn logger.with_gc_heap_usage(usage)\n}\n"
  },
  {
    "path": "src/loglib/utils.v",
    "content": "module loglib\n\nimport os\nimport io\n\npub fn check_if_terminal(w io.Writer) bool {\n\tif w is os.File {\n\t\treturn is_terminal(w.fd)\n\t}\n\treturn false\n}\n\npub fn is_terminal(fd int) bool {\n\t$if windows {\n\t\tenv_conemu := os.getenv('ConEmuANSI')\n\t\tif env_conemu == 'ON' {\n\t\t\treturn true\n\t\t}\n\t\t// 4 is enable_virtual_terminal_processing\n\t\treturn (os.is_atty(fd) & 0x0004) > 0\n\t}\n\n\treturn os.is_atty(fd) > 0\n}\n"
  },
  {
    "path": "src/lsp/README.md",
    "content": "# Description\n\n`lsp` module describes the types for the Language Server Protocol 3.17 spec.\n\n## Author\n\n2020-2021 Ned Palacios\n2023 VOSCA\n"
  },
  {
    "path": "src/lsp/capabilities.v",
    "content": "module lsp\n\npub struct WorkspaceClientCapabilities {\npub mut:\n\tapply_edit               bool          @[json: applyEdit]\n\tworkspace_edit           WorkspaceEdit @[json: workspaceEdit]\n\tdid_change_configuration DidChange     @[json: didChangeConfiguration]\n\tdid_change_watched_files DidChange     @[json: didChangeWatchedFiles]\n\tsymbol                   WorkspaceSymbolCapabilities\n\texecute_command          DidChange @[json: executeCommand]\n\tworkspace_folders        bool      @[json: workspaceFolders]\n\tconfiguration            bool\n}\n\npub struct WorkspaceSymbolCapabilities {\npub mut:\n\tdynamic_registration bool     @[json: dynamicRegistration]\n\tsymbol_kind          ValueSet @[json: symbolKind]\n}\n\npub struct ValueSet {\npub mut:\n\tvalue_set []int @[json: valueSet] // SymbolKind\n}\n\npub struct DidChange {\npub mut:\n\tdynamic_registration bool @[json: dynamicRegistration]\n}\n\npub struct TextDocumentClientCapabilities {\npub mut:\n\tcode_lens           Capability @[json: codeLens]\n\tcolor_provider      Capability @[json: colorProvider]\n\tcompletion          CompletionCapability\n\tdeclaration         LinkCapability\n\tdefinition          LinkCapability\n\tdocument_highlight  Capability               @[json: documentHighlight]\n\tdocument_link       Capability               @[json: documentLink]\n\tdocument_symbol     DocumentSymbolCapability @[json: documentSymbol]\n\tfolding_range       FoldingRangeCapabilities @[json: foldingRange]\n\tformatting          Capability\n\thover               HoverCapability\n\timplementation      LinkCapability\n\ton_type_formatting  Capability                  @[json: on_type_formatting]\n\tpublish_diagnostics PublishDiagnosticCapability @[json: publishDiagnostics]\n\trange_formatting    Capability                  @[json: rangeFormatting]\n\treferences          Capability\n\trename              RenameCapability\n\tselection_range     Capability @[json: selectionRange]\n\tsignature_help      SignatureHelpCapability\n\tsynchronization     TextDocumentSyncCapability\n\ttype_definition     LinkCapability @[json: typeDefinition]\n}\n\npub struct DocumentLinkSupport {\n\tdynamic_registration bool @[json: dynamicRegistration]\n\ttooltip_support      bool @[json: tooltip_support]\n}\n\npub struct TextDocumentSyncCapability {\npub mut:\n\tdynamic_registration bool @[json: dynamicRegistration]\n\twill_save            bool @[json: willSave]\n\twill_save_wait_until bool @[json: willSaveWaitUntil]\n\tdid_save             bool @[json: didSave]\n}\n\npub struct CompletionCapability {\npub mut:\n\tdynamic_registration bool                   @[json: dynamicRegistration]\n\tcompletion_item      CompletionItemSettings @[json: completionItem]\n\tcompletion_item_kind ValueSet               @[json: completionItemKind]\n\tcontext_support      bool                   @[json: contextSupport]\n}\n\npub struct HoverCapability {\npub mut:\n\tdynamic_registration bool     @[json: dynamicRegistration]\n\tcontent_format       []string @[json: contentFormat] // MarkupKind\n}\n\npub struct SignatureHelpCapability {\npub mut:\n\tdynamic_registration  bool @[json: dynamicRegistration]\n\tsignature_information SignatureInformationCapability @[json: signatureInformation]\n}\n\npub struct SignatureInformationCapability {\npub mut:\n\tdocument_format []string @[json: documentFormat]\n\t// MarkupKind\n\tparameter_information ParamsInfo @[json: parameterInformation]\n}\n\npub struct ParamsInfo {\npub mut:\n\tlabel_offset_support bool @[json: labelOffsetSupport]\n}\n\npub struct Capability {\npub mut:\n\tdynamic_registration bool @[json: dynamicRegistration]\n}\n\npub struct DocumentSymbolCapability {\npub mut:\n\tdynamic_registration                 bool     @[json: dynamicRegistration]\n\tsymbol_kind                          ValueSet @[json: symbolKind]\n\thierarchical_document_symbol_support bool     @[json: hierarchicalDocumentSymbolSupport]\n}\n\npub struct LinkCapability {\npub mut:\n\tdynamic_registration bool @[json: dynamicRegistration]\n\tlink_support         bool @[json: linkSupport]\n}\n\npub struct CodeActionCapability {\npub mut:\n\tdynamic_registration        bool                     @[json: dynamicRegistration]\n\tis_preferred_support        bool                     @[json: isPreferredSupport]\n\tcode_action_literal_support CodeActionLiteralSupport @[json: codeActionLiteralSupport]\n}\n\npub struct CodeActionLiteralSupport {\npub mut:\n\tcode_action_kind CodeActionKindF @[json: codeActionKind]\n}\n\npub struct CodeActionKindF {\npub mut:\n\tvalue_set []string @[json: valueSet]\n}\n\npub struct RenameCapability {\npub mut:\n\tdynamic_registration bool @[json: dynamicRegistration]\n\tprepare_support      bool @[json: prepareSupport]\n}\n\npub struct PublishDiagnosticCapability {\npub mut:\n\trelated_information bool     @[json: relatedInformation]\n\tversion_support     bool     @[json: versionSupport]\n\ttag_support         ValueSet @[json: tagSupport]\n}\n\npub struct ClientCapabilities {\npub mut:\n\tworkspace     WorkspaceClientCapabilities    @[skip]\n\ttext_document TextDocumentClientCapabilities @[json: 'textDocument']\n\twindow        WindowCapability\n\texperimental  string @[raw]\n}\n\npub struct WindowCapability {\npub mut:\n\twork_done_progress bool @[json: 'workDoneProgress']\n}\n\n@[json_as_number]\npub enum TextDocumentSyncKind {\n\tnone_       = 0\n\tfull        = 1\n\tincremental = 2\n}\n\npub struct ServerCapabilities {\npub mut:\n\ttext_document_sync                   TextDocumentSyncOptions         @[json: textDocumentSync]\n\thover_provider                       bool                            @[json: hoverProvider]\n\tinlay_hint_provider                  InlayHintOptions                @[json: inlayHintProvider]\n\tcompletion_provider                  CompletionOptions               @[json: completionProvider]\n\tsignature_help_provider              SignatureHelpOptions            @[json: signatureHelpProvider]\n\tdefinition_provider                  bool                            @[json: definitionProvider]\n\ttype_definition_provider             bool                            @[json: typeDefinitionProvider]\n\timplementation_provider              bool                            @[json: implementationProvider]\n\treferences_provider                  ReferencesOptions               @[json: referencesProvider]\n\tdocument_highlight_provider          bool                            @[json: documentHighlightProvider]\n\tdocument_symbol_provider             bool                            @[json: documentSymbolProvider]\n\tworkspace_symbol_provider            bool                            @[json: workspaceSymbolProvider]\n\tcode_action_provider                 CodeActionOptions               @[json: codeActionProvider]\n\tcode_lens_provider                   CodeLensOptions                 @[json: codeLensProvider]\n\tdocument_formatting_provider         bool                            @[json: documentFormattingProvider]\n\tdocument_on_type_formatting_provider DocumentOnTypeFormattingOptions @[json: documentOnTypeFormattingProvider]\n\trename_provider                      RenameOptions                   @[json: renameProvider]\n\tdocument_link_provider               DocumentLinkOptions             @[json: documentLinkProvider]\n\tcolor_provider                       bool                  @[json: colorProvider]\n\tdeclaration_provider                 bool                  @[json: declarationProvider]\n\texecute_command_provider             ExecuteCommandOptions @[json: executeCommandProvider]\n\tfolding_range_provider               bool                  @[json: foldingRangeProvider]\n\tsemantic_tokens_provider             SemanticTokensOptions @[json: semanticTokensProvider; omitempty]\n\texperimental                         map[string]bool\n}\n\npub struct ServerCapabilitiesWorkspace {\npub mut:\n\tworkspace_folders WorkspaceFoldersProviderSupport @[json: WorkspaceFoldersProviderSupport]\n}\n\npub struct WorkspaceFoldersProviderSupport {\npub mut:\n\tsupported            bool\n\tchange_notifications string @[json: changeNotifications]\n}\n"
  },
  {
    "path": "src/lsp/client.v",
    "content": "module lsp\n\n// method: ‘client/registerCapability’\n// response: void\npub struct RegistrationParams {\n\tregistrations []Registration\n}\n\npub struct Registration {\n\tid               int\n\tmethod           string\n\tregister_options string @[raw]\n}\n\n// base interface for registration register_options\n// pub struct TextDocumentRegistrationOptions {\n// document_selector []DocumentFilter @[json:documentSelector]\n// }\n// method: ‘client/unregisterCapability’\n// response: void\npub struct UnregistrationParams {\n\tunregistrations []Unregistration\n}\n\npub struct Unregistration {\n\tid     int\n\tmethod string\n}\n"
  },
  {
    "path": "src/lsp/code_action.v",
    "content": "module lsp\n\n// The kind of a code action.\n//\n// Kinds are a hierarchical list of identifiers separated by `.`,\n// e.g. `\"refactor.extract.function\"`.\n//\n// The set of kinds is open and client needs to announce the kinds it supports\n// to the server during initialization.\npub type CodeActionKind = string\n\npub struct CodeActionParams {\npub:\n\t// The document in which the command was invoked.\n\ttext_document TextDocumentIdentifier @[json: 'textDocument']\n\t// The range for which the command was invoked.\n\trange Range\n\t// Context carrying additional information.\n\tcontext CodeActionContext\n}\n\n// A set of predefined code action kinds.\npub enum CodeActionTriggerKind {\n\t// Code actions were explicitly requested by the user or by an extension.\n\tinvoked\n\t// Code actions were requested automatically.\n\t//\n\t// This typically happens when current selection in a file changes, but can\n\t// also be triggered when file content changes.\n\tautomatic\n}\n\n// type CodeActionKind string\npub const empty = ''\npub const quick_fix = 'quickfix'\npub const refactor = 'refactor'\npub const refactor_extract = 'refactor.extract'\npub const refactor_inline = 'refactor.inline'\npub const refactor_rewrite = 'refactor.rewrite'\npub const source = 'source'\npub const source_organize_imports = 'source.organizeImports'\n\n// Contains additional diagnostic information about the context in which\n// a code action is run.\npub struct CodeActionContext {\npub:\n\t// An array of diagnostics known on the client side overlapping the range\n\t// provided to the `textDocument/codeAction` request. They are provided so\n\t// that the server knows which errors are currently presented to the user\n\t// for the given range. There is no guarantee that these accurately reflect\n\t// the error state of the resource. The primary parameter\n\t// to compute code actions is the provided range.\n\tdiagnostics []Diagnostic\n\t// Requested kind of actions to return.\n\t//\n\t// Actions not of this kind are filtered out by the client before being\n\t// shown. So servers can omit computing them.\n\tonly []CodeActionKind\n\t// The reason why code actions were requested\n\ttrigger_kind CodeActionTriggerKind @[json: 'triggerKind']\n}\n\npub struct CodeAction {\npub:\n\t// A short, human-readable, title for this code action.\n\ttitle string\n\t// The kind of the code action.\n\t// Used to filter code actions.\n\tkind CodeActionKind\n\t// The diagnostics that this code action resolves.\n\tdiagnostics []Diagnostic\n\t// Marks this as a preferred action. Preferred actions are used by the\n\t// `auto fix` command and can be targeted by keybindings.\n\t//\n\t// A quick fix should be marked preferred if it properly addresses the\n\t// underlying error. A refactoring should be marked preferred if it is the\n\t// most reasonable choice of actions to take.\n\t//\n\t// @since 3.15.0\n\tis_preferred bool @[json: 'isPreferred']\n\t// The workspace edit this code action performs.\n\tedit WorkspaceEdit\n\t// A command this code action executes. If a code action\n\t// provides an edit and a command, first the edit is\n\t// executed and then the command.\n\tcommand Command\n\t// A data entry field that is preserved on a code action between\n\t// a `textDocument/codeAction` and a `codeAction/resolve` request.\n\t//\n\t// @since 3.16.0\n\tdata string @[raw]\n}\n\npub struct CodeActionOptions {\npub:\n\t// CodeActionKinds that this server may return.\n\t//\n\t// The list of kinds may be generic, such as `CodeActionKind.Refactor`,\n\t// or the server may list out every specific kind they provide.\n\tcode_action_kinds []string @[json: 'codeActionKinds']\n}\n"
  },
  {
    "path": "src/lsp/code_lens.v",
    "content": "module lsp\n\npub struct CodeLensOptions {\npub mut:\n\tresolve_provider   bool @[json: 'resolveProvider'; omitempty]\n\twork_done_progress bool @[json: 'workDoneProgress'; omitempty]\n}\n\n// method: ‘textDocument/codeLens’\n// response: []CodeLens | none\npub struct CodeLensParams {\n\tWorkDoneProgressParams\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n}\n\npub struct CodeLens {\npub:\n\t// The range in which this code lens is valid. Should only span a single\n\t// line.\n\trange Range\n\t// The command this code lens represents.\n\tcommand Command\n\t// A data entry field that is preserved on a code lens item between\n\t// a code lens and a code lens resolve request.\n\tdata string @[raw]\n}\n\npub struct CodeLensRegistrationOptions {\n\tdocument_selector []DocumentFilter @[json: documentSelector]\n\tresolve_provider  bool             @[json: resolveProvider]\n}\n\n// method: ‘codeLens/resolve’\n// response: CodeLens\n// request: CodeLens\n"
  },
  {
    "path": "src/lsp/color_presentation.v",
    "content": "module lsp\n\n// /**\n// * Color provider options.\n// */\n// export interface ColorProviderOptions {\n// }\n// method: ‘textDocument/colorPresentation’\n// response: []ColorPresentation\npub struct ColorPresentationParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tcolor         Color\n\trange         Range\n}\n\npub struct ColorPresentation {\n\tlabel                 string\n\ttext_edit             TextEdit   @[json: textEdit]\n\tadditional_text_edits []TextEdit @[json: additionalTextEdits]\n}\n"
  },
  {
    "path": "src/lsp/completion.v",
    "content": "module lsp\n\npub struct CompletionOptions {\npub mut:\n\tresolve_provider   bool     @[json: resolveProvider]\n\ttrigger_characters []string @[json: triggerCharacters]\n}\n\npub struct CompletionItemSettings {\n\tsnippet_support           bool     @[json: snippetSupport]\n\tcommit_characters_support bool     @[json: commitCharactersSupport]\n\tpreselect_support         bool     @[json: preselectSupport]\n\tdeprecated_support        bool     @[json: deprecatedSupport]\n\ttag_support               ValueSet @[json: tag_support]\n}\n\n// method: ‘textDocument/completion’\n// response: []CompletionItem | CompletionList | none\npub struct CompletionParams {\npub:\n\t// extend: TextDocumentPositionParams\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n\tcontext       CompletionContext\n}\n\n@[json_as_number]\npub enum CompletionTriggerKind {\n\tinvoked                            = 1\n\ttrigger_character                  = 2\n\ttrigger_for_incomplete_completions = 3\n}\n\npub struct CompletionContext {\npub:\n\ttrigger_kind      CompletionTriggerKind @[json: triggerKind]\n\ttrigger_character string                @[json: triggerCharacter]\n}\n\npub struct CompletionList {\npub:\n\tis_incomplete bool @[json: isIncomplete]\n\titems         []CompletionItem\n}\n\n@[json_as_number]\npub enum InsertTextFormat {\n\tplain_text = 1\n\tsnippet    = 2\n}\n\npub struct CompletionItemLabelDetails {\npub:\n\t// An optional string which is rendered less prominently directly after\n\t// {@link CompletionItem.label label}, without any spacing. Should be\n\t// used for function signatures or type annotations.\n\tdetail string @[omitempty]\n\t// An optional string which is rendered less prominently after\n\t// {@link CompletionItemLabelDetails.detail}. Should be used for fully qualified\n\t// names or file path.\n\tdescription string\n}\n\npub struct CompletionItem {\npub mut:\n\t// The label of this completion item.\n\t//\n\t// The label property is also by default the text that\n\t// is inserted when selecting this completion.\n\t//\n\t// If label details are provided the label itself should\n\t// be an unqualified name of the completion item.\n\tlabel string\n\t// Additional details for the label\n\tlabel_details CompletionItemLabelDetails @[json: 'labelDetails'; omitempty]\n\t// The kind of this completion item. Based of the kind\n\t// an icon is chosen by the editor. The standardized set\n\t// of available values is defined in `CompletionItemKind`.\n\tkind CompletionItemKind\n\t// A human-readable string with additional information\n\t// about this item, like type or symbol information.\n\tdetail string\n\t// A human-readable string that represents a doc-comment.\n\tdocumentation string\n\t// A string that should be used when filtering a set of\n\t// completion items. When `falsy` the label is used.\n\tfilter_text string @[json: 'filterText'; omitempty]\n\t// A string that should be inserted into a document when selecting\n\t// this completion. When omitted the label is used as the insert text\n\t// for this item.\n\t//\n\t// The `insertText` is subject to interpretation by the client side.\n\t// Some tools might not take the string literally. For example\n\t// VS Code when code complete is requested in this example\n\t// `con<cursor position>` and a completion item with an `insertText` of\n\t// `console` is provided it will only insert `sole`. Therefore it is\n\t// recommended to use `textEdit` instead since it avoids additional client\n\t// side interpretation.\n\tinsert_text string @[json: 'insertText'; omitempty]\n\t// The format of the insert text. The format applies to both the\n\t// `insertText` property and the `newText` property of a provided\n\t// `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.\n\t//\n\t// Please note that the insertTextFormat doesn't apply to\n\t// `additionalTextEdits`.\n\tinsert_text_format InsertTextFormat = .plain_text @[json: 'insertTextFormat']\n\t// How whitespace and indentation is handled during completion\n\t// item insertion. If not provided the client's default value depends on\n\t// the `textDocument.completion.insertTextMode` client capability.\n\t//\n\t// @since 3.16.0\n\t// @since 3.17.0 - support for `textDocument.completion.insertTextMode`\n\tinsert_text_mode InsertTextMode @[json: 'insertTextMode'; omitempty]\n\t// A string that should be used when comparing this item\n\t// with other items. When omitted the label is used\n\t// as the sort text for this item.\n\tsort_text string @[json: 'sortText']\n\t// text_edit TextEdit @[json:textEdit]\n\t// additional_text_edits []TextEdit @[json:additionalTextEdits]\n\t// commit_characters []string @[json:commitCharacters]\n\t// command Command\n\t// data string @[raw]\n}\n\n@[json_as_number]\npub enum InsertTextMode {\n\tas_is              = 1\n\tadjust_indentation = 2\n}\n\n@[json_as_number]\npub enum CompletionItemKind {\n\ttext           = 1\n\tmethod         = 2\n\tfunction       = 3\n\tconstructor    = 4\n\tfield          = 5\n\tvariable       = 6\n\tclass          = 7\n\tinterface_     = 8\n\tmodule_        = 9\n\tproperty       = 10\n\tunit           = 11\n\tvalue          = 12\n\tenum_          = 13\n\tkeyword        = 14\n\tsnippet        = 15\n\tcolor          = 16\n\tfile           = 17\n\treference      = 18\n\tfolder         = 19\n\tenum_member    = 20\n\tconstant       = 21\n\tstruct_        = 22\n\tevent          = 23\n\toperator       = 24\n\ttype_parameter = 25\n}\n\npub struct CompletionRegistrationOptions {\n\tdocument_selector     []DocumentFilter @[json: documentSelector]\n\ttrigger_characters    []string         @[json: triggerCharacters]\n\tall_commit_characters []string         @[json: allCommitCharacters]\n\tresolve_provider      bool             @[json: resolveProvider]\n}\n\n// method: ‘completionItem/resolve’\n// response: CompletionItem\n// request: CompletionItem\n"
  },
  {
    "path": "src/lsp/declaration.v",
    "content": "module lsp\n\n// method: ‘textDocument/declaration’\n// response: Location | []Location | []LocationLink | none\n// request: TextDocumentPositionParams\n"
  },
  {
    "path": "src/lsp/definition.v",
    "content": "module lsp\n\n// method: ‘textDocument/definition’\n// response: Location | []Location | []LocationLink | none\n// request: TextDocumentPositionParams\n// method: ‘textDocument/typeDefinition’\n// response: Location | []Location | []LocationLink | none\n// request: TextDocumentPositionParams\n"
  },
  {
    "path": "src/lsp/diagnostics.v",
    "content": "module lsp\n\n@[json_as_number]\npub enum DiagnosticTag {\n\t// Unused or unnecessary code.\n\t//\n\t// Clients are allowed to render diagnostics with this tag faded out\n\t// instead of having an error squiggle.\n\tunnecessary = 1\n\t// Deprecated or obsolete code.\n\t//\n\t// Clients are allowed to rendered diagnostics with this tag strike through.\n\tdeprecated\n}\n\npub struct CodeDescription {\npub mut:\n\thref string = 'https://github.com/vlang/v/blob/master/doc/docs.md'\n}\n\npub struct Diagnostic {\npub mut:\n\t// The range at which the message applies.\n\trange Range\n\t// The diagnostic's severity. Can be omitted. If omitted it is up to the\n\t// client to interpret diagnostics as error, warning, info or hint.\n\tseverity DiagnosticSeverity\n\t// The diagnostic's code, which might appear in the user interface.\n\tcode string\n\t// An optional property to describe the error code.\n\tcode_description CodeDescription @[json: 'codeDescription']\n\t// A human-readable string describing the source of this\n\t// diagnostic, e.g. 'typescript' or 'super lint'.\n\tsource string\n\t// The diagnostic's message.\n\tmessage string\n\t// Additional metadata about the diagnostic.\n\ttags []DiagnosticTag @[json: 'tags']\n\t// An array of related diagnostic information, e.g. when symbol-names within\n\t// a scope collide all definitions can be marked via this property.\n\trelated_information []DiagnosticRelatedInformation @[json: 'relatedInformation']\n\t// A data entry field that is preserved between a\n\t// `textDocument/publishDiagnostics` notification and\n\t// `textDocument/codeAction` request.\n\t//\n\t// @since 3.16.0\n\tdata string @[raw]\n}\n\n@[json_as_number]\npub enum DiagnosticSeverity {\n\terror = 1\n\twarning\n\tinformation\n\thint\n}\n\n// Represents a related message and source code location for a diagnostic.\n// This should be used to point to code locations that cause or are related to\n// a diagnostics, e.g when duplicating a symbol in a scope.\npub struct DiagnosticRelatedInformation {\n\t// The location of this related diagnostic information.\n\tlocation Location\n\t// The message of this related diagnostic information.\n\tmessage string\n}\n\n// method: ‘textDocument/publishDiagnostics’\npub struct PublishDiagnosticsParams {\npub:\n\turi         DocumentUri\n\tdiagnostics []Diagnostic\n}\n"
  },
  {
    "path": "src/lsp/document_color.v",
    "content": "module lsp\n\n// method: ‘textDocument/documentColor’\n// response: []ColorInformation\npub struct DocumentColorParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n}\n\npub struct ColorInformation {\n\trange Range\n\tcolor Color\n}\n\npub struct Color {\n\tred   int\n\tgreen int\n\tblue  int\n\talpha int\n}\n"
  },
  {
    "path": "src/lsp/document_highlight.v",
    "content": "module lsp\n\n// method: ‘textDocument/documentHighlight’\n// response: []DocumentHighlight | none\n// request: TextDocumentPositionParams\npub struct DocumentHighlight {\npub:\n\trange Range\n\tkind  DocumentHighlightKind\n}\n\n@[json_as_number]\npub enum DocumentHighlightKind {\n\ttext  = 1\n\tread  = 2\n\twrite = 3\n}\n"
  },
  {
    "path": "src/lsp/document_link.v",
    "content": "module lsp\n\npub struct DocumentLinkOptions {\n\tresolve_provider bool @[json: resolveProvider]\n}\n\n// method: ‘textDocument/documentLink’\n// response: []DocumentLink | none\npub struct DocumentLinkParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n}\n\npub struct DocumentLink {\n\trange  Range\n\ttarget DocumentUri\n\tdata   string @[raw]\n}\n\npub struct DocumentLinkRegistrationOptions {\n\tdocument_selector []DocumentFilter @[json: documentSelector]\n\tresolve_provider  bool             @[json: resolveProvider]\n}\n\n// method: ‘documentLink/resolve’\n// response: DocumentLink\n// request: DocumentLink\n"
  },
  {
    "path": "src/lsp/document_symbol.v",
    "content": "module lsp\n\n// method: ‘textDocument/documentSymbol’\n// response: []DocumentSymbol | []SymbolInformation | none\npub struct DocumentSymbolParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n}\n\n@[json_as_number]\npub enum SymbolKind {\n\tfile           = 1\n\tmodule_        = 2\n\tnamespace      = 3\n\tpackage        = 4\n\tclass          = 5\n\tmethod         = 6\n\tproperty       = 7\n\tfield          = 8\n\tconstructor    = 9\n\tenum_          = 10\n\tinterface_     = 11\n\tfunction       = 12\n\tvariable       = 13\n\tconstant       = 14\n\tstring         = 15\n\tnumber         = 16\n\tboolean        = 17\n\tarray          = 18\n\tobject         = 19\n\tkey            = 20\n\tnull           = 21\n\tenum_member    = 22\n\tstruct_        = 23\n\tevent          = 24\n\toperator       = 25\n\ttype_parameter = 26\n}\n\npub struct DocumentSymbol {\npub mut:\n\t// The name of this symbol. Will be displayed in the user interface and\n\t// therefore must not be an empty string or a string only consisting of\n\t// white spaces.\n\tname string\n\t//  More detail for this symbol, e.g the signature of a function.\n\tdetail     string @[omitempty]\n\tkind       SymbolKind\n\tdeprecated bool @[omitempty]\n\t// The range enclosing this symbol not including leading/trailing whitespace\n\t// but everything else like comments. This information is typically used to\n\t// determine if the clients cursor is inside the symbol to reveal in the\n\t// symbol in the UI.\n\trange Range\n\t// The range that should be selected and revealed when this symbol is being\n\t// picked, e.g. the name of a function. Must be contained by the `range`.\n\tselection_range Range @[json: 'selectionRange'; omitempty]\n\t// Children of this symbol, e.g. properties of a class.\n\tchildren []DocumentSymbol @[omitempty]\n}\n"
  },
  {
    "path": "src/lsp/ext.v",
    "content": "module lsp\n\npub struct ServerStatusParams {\npub:\n\thealth    string // \"ok\" | \"warning\" | \"error\";\n\tquiescent bool\n\tmessage   string @[omitempty]\n}\n"
  },
  {
    "path": "src/lsp/file_resource.v",
    "content": "module lsp\n\npub struct CreateFileOptions {\n\toverwrite        bool\n\tignore_if_exists bool @[json: ignoreIfExists]\n}\n\npub struct CreateFile {\n\tkind    string = 'create'\n\turi     DocumentUri\n\toptions CreateFileOptions\n}\n\npub struct RenameFileOptions {\n\toverwrite        bool\n\tignore_if_exists bool @[json: ignoreIfExists]\n}\n\npub struct RenameFile {\n\tkind    string = 'rename'\n\told_uri DocumentUri @[json: oldUri]\n\tnew_uri DocumentUri @[json: newUri]\n\toptions RenameFileOptions\n}\n\npub struct DeleteFileOptions {\n\trecursive        bool\n\tignore_if_exists bool @[json: ignoreIfExists]\n}\n\npub struct DeleteFile {\n\tkind    string = 'delete'\n\turi     DocumentUri\n\toptions DeleteFileOptions\n}\n"
  },
  {
    "path": "src/lsp/folding_range.v",
    "content": "module lsp\n\ntype FoldingRangeKind = string\n\npub struct FoldingRangeKindCapabilities {\npub:\n\t// The folding range kind values the client supports. When this\n\t// property exists the client also guarantees that it will\n\t// handle values outside its set gracefully and falls back\n\t// to a default value when unknown.\n\tvalue_set []FoldingRangeKind @[json: 'valueSet'; omitempty]\n}\n\npub struct FoldingRangeValuesCapabilities {\npub:\n\t// If set, the client signals that it supports setting collapsedText on\n\t// folding ranges to display custom labels instead of the default text.\n\t// @since 3.17.0\n\tcollapsed_text bool @[json: 'collapsedText'; omitempty]\n}\n\npub struct FoldingRangeCapabilities {\npub:\n\t// The maximum number of folding ranges that the client prefers to receive\n\t// per document. The value serves as a hint, servers are free to follow the\n\t// limit.\n\trange_limit u32 @[json: 'rangeLimit'; omitempty]\n\t// If set, the client signals that it only supports folding complete lines.\n\t// If set, client will ignore specified `startCharacter` and `endCharacter`\n\t// properties in a FoldingRange.\n\tline_folding_only bool @[json: 'lineFoldingOnly'; omitempty]\n\t// Specific options for the folding range kind.\n\tfolding_range_kind FoldingRangeKindCapabilities @[json: 'foldingRangeKind'; omitempty]\n\t// Specific options for the folding range.\n\tfolding_range FoldingRangeValuesCapabilities @[json: 'foldingRange'; omitempty]\n}\n\npub struct FoldingRangeParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: 'textDocument']\n}\n\n// Folding range for a comment\npub const folding_range_kind_comment = 'comment'\n// Folding range for imports or includes\npub const folding_range_kind_imports = 'imports'\n// Folding range for a region (e.g. `#region`)\npub const folding_range_kind_region = 'region'\n\n// Represents a folding range. To be valid, start and end line must be bigger\n// than zero and smaller than the number of lines in the document. Clients\n// are free to ignore invalid ranges.\npub struct FoldingRange {\npub:\n\t// The zero-based start line of the range to fold. The folded area starts\n\t// after the line's last character. To be valid, the end must be zero or\n\t// larger and smaller than the number of lines in the document.\n\tstart_line int @[json: 'startLine']\n\t// The zero-based character offset from where the folded range starts. If\n\t// not defined, defaults to the length of the start line.\n\tstart_character int @[json: 'startCharacter'; omitempty]\n\t// The zero-based end line of the range to fold. The folded area ends with\n\t// the line's last character. To be valid, the end must be zero or larger\n\t// and smaller than the number of lines in the document.\n\tend_line int @[json: 'endLine']\n\t// The zero-based character offset before the folded range ends. If not\n\t// defined, defaults to the length of the end line.\n\tend_character int @[json: 'endCharacter'; omitempty]\n\t// Describes the kind of the folding range such as `comment` or `region`.\n\t// The kind is used to categorize folding ranges and used by commands like\n\t// 'Fold all comments'. See [FoldingRangeKind](#FoldingRangeKind) for an\n\t// enumeration of standardized kinds.\n\tkind string\n\t// The text that the client should show when the specified range is\n\t// collapsed. If not defined or not supported by the client, a default\n\t// will be chosen by the client.\n\t//\n\t// @since 3.17.0 - proposed\n\tcollapsed_text string @[json: 'collapsedText'; omitempty]\n}\n"
  },
  {
    "path": "src/lsp/formatting.v",
    "content": "module lsp\n\n// method: ‘textDocument/formatting’\n// response: []TextEdit | none\npub struct DocumentFormattingParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\toptions       FormattingOptions\n}\n\npub struct FormattingOptions {\n\ttab_size      int  @[json: tabSize]\n\tinsert_spaces bool @[json: insertSpaces]\n\t// [key] bool | number | string\n}\n\n// method: ‘textDocument/rangeFormatting’\n// response: []TextEdit | none\npub struct DocumentRangeFormattingParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\trange         Range\n\toptions       FormattingOptions\n}\n\npub struct DocumentOnTypeFormattingOptions {\n\tfirst_trigger_character string   @[json: firstTriggerCharacter]\n\tmore_trigger_character  []string @[json: moreTriggerCharacter]\n}\n\n// method: ‘textDocument/onTypeFormatting’\n// response: []TextEdit | none\npub struct DocumentOnTypeFormattingParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n\tch            string\n\toptions       FormattingOptions\n}\n\npub struct DocumentOnTypeFormattingRegistrationOptions {\n\tdocument_selector       []DocumentFilter @[json: documentSelector]\n\tfirst_trigger_character string           @[json: firstTriggerCharacter]\n\tmore_trigger_character  []string         @[json: moreTriggerCharacter]\n}\n"
  },
  {
    "path": "src/lsp/hover.v",
    "content": "module lsp\n\npub struct HoverSettings {\n\tdynamic_registration bool     @[json: dynamicRegistration]\n\tcontent_format       []string @[json: contentFormat]\n}\n\n// method: ‘textDocument/hover’\n// response: Hover | none\n// request: TextDocumentPositionParams\npub struct HoverParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n}\n\ntype HoverResponseContent = MarkedString | MarkupContent | []MarkedString | string\n\npub struct Hover {\npub:\n\tcontents HoverResponseContent\n\trange    Range\n}\n\n// pub type MarkedString = string | MarkedString\npub struct MarkedString {\n\tlanguage string\n\tvalue    string\n}\n\npub fn hover_v_marked_string(text string) HoverResponseContent {\n\treturn HoverResponseContent(MarkedString{\n\t\tlanguage: 'v'\n\t\tvalue:    text\n\t})\n}\n\npub fn hover_markdown_string(text string) HoverResponseContent {\n\treturn HoverResponseContent(MarkupContent{\n\t\tkind:  markup_kind_markdown\n\t\tvalue: text\n\t})\n}\n"
  },
  {
    "path": "src/lsp/implementation.v",
    "content": "module lsp\n\n// method: ‘textDocument/implementation’\n// response: Location | []Location | []LocationLink | none\n// request: TextDocumentPositionParams\n"
  },
  {
    "path": "src/lsp/initialize.v",
    "content": "module lsp\n\n// TODO: These LSPAny need to change to `?LSPAny` too.\ntype LSPAny = []LSPAny | map[string]LSPAny | f64 | bool | string\n\n// method: ‘initialize’\n// response: InitializeResult\npub struct InitializeParams {\npub mut:\n\tprocess_id  int = -2         @[json: processId]\n\tclient_info ClientInfo  @[json: clientInfo]\n\troot_uri    DocumentUri @[json: rootUri]\n\troot_path   DocumentUri @[json: rootPath]\n\t// TODO: Change this to `?LSPAny` once V fixed its JSON decoder codegen. (or shall we use json2?)\n\tinitialization_options LSPAny @[json: initializationOptions]\n\tcapabilities           ClientCapabilities\n\ttrace                  string\n\tworkspace_folders      []WorkspaceFolder @[skip]\n}\n\npub struct ClientInfo {\npub mut:\n\tname    string @[json: name]\n\tversion string @[json: version]\n}\n\npub struct ServerInfo {\npub mut:\n\tname    string\n\tversion string\n}\n\npub struct InitializeResult {\npub:\n\tcapabilities ServerCapabilities\n\tserver_info  ServerInfo @[json: 'serverInfo'; omitempty]\n}\n\n// method: ‘initialized’\n// notification\n// pub struct InitializedParams {}\n\n@[json_as_number]\npub enum InitializeErrorCode {\n\tunknown_protocol_version = 1\n}\n\npub struct InitializeError {\n\tretry bool\n}\n\n/*\n*\n * The kind of resource operations supported by the client.\n*/\n\n@[json_as_number]\npub enum ResourceOperationKind {\n\tcreate\n\trename\n\tdelete\n}\n\n@[json_as_number]\npub enum FailureHandlingKind {\n\tabort\n\ttransactional\n\tundo\n\ttext_only_transactional\n}\n\npub struct ExecuteCommandOptions {\npub:\n\t// The commands to be executed on the server\n\tcommands []string\n}\n\npub struct StaticRegistrationOptions {\n\tid string\n}\n\n// method: ‘shutdown’\n// response: none\n// method: ‘exit’\n// response: none\n"
  },
  {
    "path": "src/lsp/inlay_hint.v",
    "content": "module lsp\n\npub type InlineHintLabel = []InlayHintLabelPart | string\npub type InlineHintTooltip = MarkupContent | string\n\npub struct InlayHint {\npub:\n\t// The position of this hint.\n\tposition Position\n\t// The label of this hint. A human readable string or an array of\n\t// InlayHintLabelPart label parts.\n\t//\n\t// *Note* that neither the string nor the label part can be empty.\n\tlabel InlineHintLabel\n\t// The kind of this hint. Can be omitted in which case the client\n\t// should fall back to a reasonable default.\n\tkind InlayHintKind\n\t// Optional text edits that are performed when accepting this inlay hint.\n\t//\n\t// *Note* that edits are expected to change the document so that the inlay\n\t// hint (or its nearest variant) is now part of the document and the inlay\n\t// hint itself is now obsolete.\n\ttext_edits []TextEdit @[json: 'textEdits'; omitempty]\n\t// The tooltip text when you hover over this item.\n\ttooltip InlineHintTooltip @[json: 'tooltip'; omitempty]\n\t// Render padding before the hint.\n\t//\n\t// Note: Padding should use the editor's background color, not the\n\t// background color of the hint itself. That means padding can be used\n\t// to visually align/separate an inlay hint.\n\tpadding_left bool @[json: 'paddingLeft'; omitempty]\n\t// Render padding after the hint.\n\t//\n\t// Note: Padding should use the editor's background color, not the\n\t// background color of the hint itself. That means padding can be used\n\t// to visually align/separate an inlay hint.\n\tpadding_right bool @[json: 'paddingRight'; omitempty]\n\t// A data entry field that is preserved on an inlay hint between\n\t// a `textDocument/inlayHint` and a `inlayHint/resolve` request.\n\tdata string @[raw]\n}\n\npub struct InlayHintClientCapabilities {\npub:\n\t// Whether inlay hints support dynamic registration.\n\tdynamic_registration bool @[json: 'dynamicRegistration']\n\t// Indicates which properties a client can resolve lazily on an inlay\n\t// hint.\n\tresolve_support bool @[json: 'resolveSupport']\n}\n\n@[json_as_number]\npub enum InlayHintKind {\n\ttype_\n\tparameter\n}\n\npub struct InlayHintLabelPart {\npub:\n\t// The value of this label part.\n\tvalue string\n\t// The tooltip text when you hover over this label part. Depending on\n\t// the client capability `inlayHint.resolveSupport` clients might resolve\n\t// this property late using the resolve request.\n\ttooltip MarkupContent @[omitempty]\n\t// An optional source code location that represents this\n\t// label part.\n\t//\n\t// The editor will use this location for the hover and for code navigation\n\t// features: This part will become a clickable link that resolves to the\n\t// definition of the symbol at the given location (not necessarily the\n\t// location itself), it shows the hover that shows at the given location,\n\t// and it shows a context menu with further code navigation commands.\n\t//\n\t// Depending on the client capability `inlayHint.resolveSupport` clients\n\t// might resolve this property late using the resolve request.\n\tlocation Location @[omitempty]\n\t// An optional command for this label part.\n\t//\n\t// Depending on the client capability `inlayHint.resolveSupport` clients\n\t// might resolve this property late using the resolve request.\n\tcommand Command @[omitempty]\n}\n\n// A parameter literal used in inlay hint requests.\n//\n// @since 3.17.0\npub struct InlayHintOptions {\npub:\n\tresolve_provider bool @[json: 'resolveProvider']\n}\n\n// A parameter literal used in inlay hint requests.\n//\n// @since 3.17.0\npub struct InlayHintParams {\npub:\n\t// The text document.\n\ttext_document TextDocumentIdentifier @[json: 'textDocument']\n\t// The document range for which inlay hints should be computed.\n\trange Range\n}\n"
  },
  {
    "path": "src/lsp/log/log.v",
    "content": "module log\n\nimport os\nimport time\nimport io\nimport jsonrpc\nimport strings\n\npub struct LogRecorder {\nmut:\n\tfile        os.File\n\tbuffer      strings.Builder\n\tfile_opened bool\n\tenabled     bool\npub mut:\n\tfile_path string\n}\n\n@[json_as_number]\npub enum TransportKind {\n\tsend\n\treceive\n}\n\nstruct Payload {\n\tid     int\n\tmethod string\n\tresult string @[raw]\n\tparams string @[raw]\n}\n\n@[json_as_number]\npub enum LogKind {\n\tsend_notification\n\trecv_notification\n\trecv_request\n\tsend_response\n}\n\npub fn (lk LogKind) str() string {\n\treturn match lk {\n\t\t.send_notification { 'send-notification' }\n\t\t.recv_notification { 'recv-notification' }\n\t\t.recv_request { 'recv-request' }\n\t\t.send_response { 'send-response' }\n\t}\n}\n\npub struct LogItem {\n\tkind      LogKind\n\ttimestamp time.Time = time.now()\n\tpayload   []u8 // raw JSON\n}\n\n// json is a JSON string representation of the log item.\npub fn (li LogItem) encode_json(mut wr io.Writer) ! {\n\twr.write('{\"kind\":\"${li.kind}\",\"timestamp\":${li.timestamp.unix()},\"payload\":'.bytes())!\n\twr.write(li.payload)!\n\twr.write('}\\n'.bytes())!\n}\n\npub fn new() &LogRecorder {\n\treturn &LogRecorder{\n\t\tfile_opened: false\n\t\tenabled:     true\n\t\tbuffer:      strings.new_builder(4096)\n\t}\n}\n\npub fn (l &LogRecorder) is_enabled() bool {\n\treturn l.enabled\n}\n\n// set_logpath sets the filepath of the log file and opens the file.\npub fn (mut l LogRecorder) set_logpath(path string) ! {\n\tif l.file_opened {\n\t\tl.close()\n\t}\n\n\tl.file = os.open_append(os.real_path(path))!\n\tl.file_path = path\n\tl.file_opened = true\n\tl.enabled = true\n}\n\n// flush flushes the contents of the log file into the disk.\npub fn (mut l LogRecorder) flush() {\n\tl.file.flush()\n}\n\n// close closes the log file.\npub fn (mut l LogRecorder) close() {\n\tif !l.file_opened {\n\t\treturn\n\t}\n\n\tl.file_opened = false\n\tl.file.close()\n}\n\n// enable enables/starts the logging.\npub fn (mut l LogRecorder) enable() {\n\tl.enabled = true\n}\n\n// disable disables/stops the logging.\npub fn (mut l LogRecorder) disable() {\n\tl.enabled = false\n}\n\n// write writes the log item into the log file or in the\n// buffer if the file is not opened yet.\n@[manualfree]\nfn (mut l LogRecorder) log(item LogItem) {\n\tif !l.enabled {\n\t\treturn\n\t} else if l.file_opened {\n\t\tif l.buffer.len != 0 {\n\t\t\tunsafe {\n\t\t\t\tl.file.write_ptr(l.buffer.data, l.buffer.len)\n\t\t\t\tl.buffer.go_back_to(0)\n\t\t\t}\n\t\t}\n\t\titem.encode_json(mut l.file) or { eprintln(err) }\n\t\tl.flush()\n\t} else {\n\t\titem.encode_json(mut l.buffer) or { eprintln(err) }\n\t}\n}\n\n// as a JSON-RPC interceptor\nconst event_prefix = '$/lspLogger'\n\npub const set_logpath_event = '${event_prefix}/setPath'\n\npub const close_event = '${event_prefix}/close'\n\npub const state_event = '${event_prefix}/state'\n\npub fn (mut l LogRecorder) on_event(name string, data jsonrpc.InterceptorData) ! {\n\tif name == set_logpath_event && data is string {\n\t\tl.set_logpath(data)!\n\t} else if name == close_event {\n\t\tl.close()\n\t} else if name == state_event && data is bool {\n\t\tif data {\n\t\t\tl.enable()\n\t\t} else {\n\t\t\tl.disable()\n\t\t}\n\t}\n}\n\npub fn (_ &LogRecorder) on_raw_request(req []u8) ! {}\n\npub fn (_ &LogRecorder) on_raw_response(raw_resp []u8) ! {}\n\npub fn (mut l LogRecorder) on_request(req &jsonrpc.Request) ! {\n\tlog_kind := if req.id.len == 0 {\n\t\tLogKind.recv_notification\n\t} else {\n\t\tLogKind.recv_request\n\t}\n\tl.log(kind: log_kind, payload: req.json().bytes())\n}\n\npub fn (mut l LogRecorder) on_encoded_response(resp []u8) {\n\tif 15 < resp.len && 23 < resp.len && resp[15..23].bytestr() == ',\"method\"' {\n\t\tl.log(kind: .send_response, payload: resp)\n\t} else {\n\t\tl.log(kind: .send_notification, payload: resp)\n\t}\n}\n"
  },
  {
    "path": "src/lsp/log/log_test.v",
    "content": "module log\n\nimport json\n\nstruct TestLogItem {\n\tkind    string\n\tpayload string\n}\n\nfn test_notification_send() {\n\tmut lg := new()\n\n\tlg.log(kind: .send_notification, payload: '\"Hello!\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'send-notification'\n\tassert result.payload == 'Hello!'\n}\n\nfn test_notification_receive() {\n\tmut lg := new()\n\n\tlg.log(kind: .recv_notification, payload: '\"Received!\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'recv-notification'\n\tassert result.payload == 'Received!'\n}\n\nfn test_request_send() {\n\tmut lg := new()\n\n\tlg.log(kind: .recv_request, payload: '\"Request sent.\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'recv-request'\n\tassert result.payload == 'Request sent.'\n}\n\nfn test_request_receive() {\n\tmut lg := new()\n\n\tlg.log(kind: .recv_request, payload: '\"Request received.\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'recv-request'\n\tassert result.payload == 'Request received.'\n}\n\nfn test_response_send() {\n\tmut lg := new()\n\n\tlg.log(kind: .send_response, payload: '\"Response sent.\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'send-response'\n\tassert result.payload == 'Response sent.'\n}\n\nfn test_response_receive() {\n\tmut lg := new()\n\n\tlg.log(kind: .send_response, payload: '\"Response received.\"'.bytes())\n\tbuf := lg.buffer.str()\n\tresult := json.decode(TestLogItem, buf)!\n\n\tassert result.kind == 'send-response'\n\tassert result.payload == 'Response received.'\n}\n"
  },
  {
    "path": "src/lsp/lsp.v",
    "content": "module lsp\n\nimport os\n\npub type DocumentUri = string\n\npub fn (du DocumentUri) dir() string {\n\treturn os.dir(du)\n}\n\npub fn (du DocumentUri) path() string {\n\tscheme := 'file://'\n\tif !du.starts_with(scheme) {\n\t\treturn ''\n\t}\n\n\tmut authority := du.all_after(scheme).all_before('/')\n\tmut path := du.all_after(scheme).all_after('/')\n\n\tauthority = unescape(authority)\n\tpath = unescape(path)\n\n\tmut result := ''\n\t$if windows {\n\t\tif authority != '' && path != '' {\n\t\t\tresult = '//${authority}/${path}'\n\t\t} else if path[0].is_letter() && path[1] == `:` {\n\t\t\t// convert driver name to upper case\n\t\t\tdrive_name := if path[0].is_capital() {\n\t\t\t\tpath[0]\n\t\t\t} else {\n\t\t\t\tpath[0] - 32\n\t\t\t}\n\n\t\t\tresult = rune(drive_name).str() + path[1..]\n\t\t} else {\n\t\t\tresult = path\n\t\t}\n\n\t\tresult = result.replace('/', '\\\\')\n\t} $else {\n\t\tresult = '/' + path\n\t}\n\n\treturn result\n}\n\npub fn (du DocumentUri) dir_path() string {\n\treturn os.dir(du.path())\n}\n\npub fn (du DocumentUri) normalize() DocumentUri {\n\treturn document_uri_from_path(du.path())\n}\n\nfn escape(s string) string {\n\tbyte_array := s.bytes()\n\n\treturn byte_array.map(if it.is_alnum() || it in [`-`, `.`, `_`, `~`, `/`] {\n\t\trune(it).str()\n\t} else {\n\t\t'%${it:02X}'\n\t})\n\t\t.join('')\n}\n\nfn unescape(s string) string {\n\trune_array := s.runes()\n\tmut results := []u8{}\n\n\tfor i := 0; i < rune_array.len; i++ {\n\t\tif rune_array[i] != `%` {\n\t\t\tresults << rune_array[i].bytes()\n\t\t} else {\n\t\t\tv1_rune := rune_array[i + 1] or { `\\0` }\n\t\t\tv2_rune := rune_array[i + 2] or { `\\0` }\n\n\t\t\tv1 := try_into_hex_int(v1_rune) or {\n\t\t\t\tresults << rune_array[i].bytes()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tv2 := try_into_hex_int(v2_rune) or {\n\t\t\t\tresults << rune_array[i].bytes()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tv := (v1 << 4) + v2\n\n\t\t\tresults << v\n\t\t\ti += 2\n\t\t}\n\t}\n\n\treturn results.bytestr()\n}\n\nfn try_into_hex_int(r rune) ?rune {\n\treturn if r >= `0` && r <= `9` {\n\t\tr - `0`\n\t} else if r >= `A` && r <= `F` {\n\t\tr - `A` + 10\n\t} else if r >= `a` && r <= `f` {\n\t\tr - `a` + 10\n\t} else {\n\t\tnone\n\t}\n}\n\npub fn document_uri_from_path(path string) DocumentUri {\n\tscheme := 'file://'\n\tis_has_scheme := path.starts_with(scheme)\n\n\tmut fixed_path := if is_has_scheme {\n\t\tpath.all_after(scheme)\n\t} else {\n\t\tpath\n\t}\n\n\tmut authority := ''\n\t$if windows {\n\t\tfixed_path = fixed_path.replace('\\\\', '/')\n\n\t\t// UNC paths for accessing network resources\n\t\tif !is_has_scheme && fixed_path.starts_with('//') {\n\t\t\tauthority = fixed_path.find_between('//', '/')\n\t\t\tfixed_path = fixed_path.all_after('//').all_after('/')\n\t\t\tif fixed_path == '' {\n\t\t\t\tfixed_path = '/'\n\t\t\t}\n\t\t}\n\t}\n\n\tmut is_need_prepend_slash := false\n\t$if windows {\n\t\t// paths start with '/' without specifying drive name are paths\n\t\t// relative to root of current drive.\n\t\t// an extra '/' needs to be prepended.\n\t\tis_need_prepend_slash = !fixed_path.starts_with('/')\n\t\t\t|| (fixed_path[1] != `/` && fixed_path[2] != `:`)\n\t} $else {\n\t\tis_need_prepend_slash = !fixed_path.starts_with('/')\n\t}\n\n\tif is_need_prepend_slash {\n\t\tfixed_path = '/' + fixed_path\n\t}\n\n\t$if windows {\n\t\t// convert driver name to lower case, e.g. /C:/foo ->  /c:/foo\n\t\tif fixed_path[2] == `:` && fixed_path[1].is_letter() {\n\t\t\tdriver_name := if fixed_path[1].is_capital() {\n\t\t\t\tfixed_path[1] + 32\n\t\t\t} else {\n\t\t\t\tfixed_path[1]\n\t\t\t}\n\t\t\tfixed_path = '/${rune(driver_name).str()}${fixed_path[2..]}'\n\t\t}\n\t}\n\n\turi := scheme + escape(authority) + escape(fixed_path)\n\treturn uri\n}\n\npub struct NotificationMessage {\n\tmethod string\n\tparams string @[raw]\n}\n\n// // method: $/cancelRequest\npub struct CancelParams {\n\tid int\n}\n\npub struct Command {\npub:\n\ttitle     string\n\tcommand   string\n\targuments []string\n}\n\npub struct DocumentFilter {\n\tlanguage string\n\tscheme   string\n\tpattern  string\n}\n\npub struct TextDocumentRegistrationOptions {\n\tdocument_selector []DocumentFilter @[json: documentSelector]\n}\n"
  },
  {
    "path": "src/lsp/lsp_test.v",
    "content": "module lsp\n\nfn test_document_uri_from_path() {\n\tinput := '/foo/bar/test.v'\n\turi := document_uri_from_path(input)\n\t$if windows {\n\t\tassert uri == 'file:////foo/bar/test.v'\n\t} $else {\n\t\tassert uri == 'file:///foo/bar/test.v'\n\t}\n\tassert document_uri_from_path(uri) == uri\n}\n\nfn test_document_uri_from_path_windows() {\n\t$if !windows {\n\t\treturn\n\t}\n\n\tinput := [\n\t\t'C:\\\\coding\\\\test.v',\n\t\t'file:///C:/my/files',\n\t\tr'\\\\server\\share\\foo',\n\t]\n\texpected := [\n\t\t'file:///c%3A/coding/test.v',\n\t\t'file:///c%3A/my/files',\n\t\t'file://server/share/foo',\n\t]\n\n\tfor i in 0 .. input.len {\n\t\tassert document_uri_from_path(input[i]) == expected[i]\n\t}\n}\n\nfn test_document_uri_unicode() {\n\tinput := [\n\t\t'/usr/home/你好世界',\n\t\tr'C:/files/C%3A%5Cfiles',\n\t]\n\tmut expected := []string{}\n\t$if windows {\n\t\texpected << 'file:////usr/home/%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C'\n\t\texpected << 'file:///c%3A/files/C%253A%255Cfiles'\n\t} $else {\n\t\texpected << 'file:///usr/home/%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C'\n\t\texpected << 'file:///C%3A/files/C%253A%255Cfiles'\n\t}\n\n\tfor i in 0 .. input.len {\n\t\tassert document_uri_from_path(input[i]) == expected[i]\n\t}\n}\n\nfn test_document_uri_path() {\n\tinput := [\n\t\t'file:///baz/foo/hello.v',\n\t\t'file:///C%3A/upper_case/files',\n\t\t'file:///c%3A/lower_case/files',\n\t\t'file://server/share/foo',\n\t\t'file:///usr/home/%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C',\n\t]\n\tmut expected := []string{}\n\t$if windows {\n\t\texpected << r'baz\\foo\\hello.v'\n\t\texpected << r'C:\\upper_case\\files'\n\t\texpected << r'C:\\lower_case\\files'\n\t\texpected << r'\\\\server\\share\\foo'\n\t\texpected << r'usr\\home\\你好世界'\n\t} $else {\n\t\texpected << '/baz/foo/hello.v'\n\t\texpected << '/C:/upper_case/files'\n\t\texpected << '/c:/lower_case/files'\n\t\texpected << '/share/foo'\n\t\texpected << '/usr/home/你好世界'\n\t}\n\n\tfor i in 0 .. input.len {\n\t\tassert DocumentUri(input[i]).path() == expected[i]\n\t}\n}\n"
  },
  {
    "path": "src/lsp/progress.v",
    "content": "module lsp\n\nimport rand\nimport crypto.md5\n\npub type ProgressToken = string\n\npub fn (t ProgressToken) empty() bool {\n\treturn t == ''\n}\n\npub fn generate_progress_token() ProgressToken {\n\tvalue := rand.intn(1000000) or { 0 }\n\treturn md5.hexhash(value.str())\n}\n\npub struct WorkDoneProgressParams {\npub:\n\twork_done_token ProgressToken @[json: 'workDoneToken'; omitempty]\n}\n\npub struct PartialResultParams {\npub:\n\tpartial_result_token ProgressToken @[json: 'partialResultToken'; omitempty]\n}\n\npub struct WorkDoneProgressCreateParams {\npub:\n\ttoken ProgressToken\n}\n\npub struct ProgressParams {\npub:\n\ttoken ProgressToken\n\tvalue WorkDoneProgressPayload\n}\n\npub struct WorkDoneProgressPayload {\npub:\n\t// begin / report / end\n\tkind string\n\t// Mandatory title of the progress operation. Used to briefly inform about\n\t// the kind of operation being performed.\n\t//\n\t// Examples: \"Indexing\" or \"Linking dependencies\".\n\ttitle string @[omitempty]\n\t// Controls if a cancel button should show to allow the user to cancel the\n\t// long running operation. Clients that don't support cancellation are\n\t// allowed to ignore the setting.\n\tcancellable bool @[omitempty]\n\t// Optional, more detailed associated progress message. Contains\n\t// complementary information to the `title`.\n\t//\n\t// Examples: \"3/25 files\", \"project/src/module2\", \"node_modules/some_dep\".\n\t// If unset, the previous progress message (if any) is still valid.\n\tmessage string @[omitempty]\n\t// Optional progress percentage to display (value 100 is considered 100%).\n\t// If not provided infinite progress is assumed and clients are allowed\n\t// to ignore the `percentage` value in subsequent in report notifications.\n\t//\n\t// The value should be steadily rising. Clients are free to ignore values\n\t// that are not following this rule. The value range is [0, 100]\n\tpercentage u32\n}\n\npub struct WorkDoneProgressBegin {\n\tWorkDoneProgressPayload\npub:\n\tkind string = 'begin'\n}\n\npub struct WorkDoneProgressReport {\n\tWorkDoneProgressPayload\npub:\n\tkind string = 'report'\n}\n\npub struct WorkDoneProgressEnd {\n\tWorkDoneProgressPayload\n\tkind string = 'end'\n}\n"
  },
  {
    "path": "src/lsp/references.v",
    "content": "module lsp\n\npub struct ReferencesOptions {\npub:\n\twork_done_progress bool @[json: 'workDoneProgress']\n}\n\n// method: ‘textDocument/references’\n// response: []Location | none\npub struct ReferenceParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n\tcontext       ReferenceContext\n}\n\npub struct ReferenceContext {\n\tinclude_declaration bool\n}\n"
  },
  {
    "path": "src/lsp/rename.v",
    "content": "module lsp\n\npub struct RenameOptions {\npub:\n\tprepare_provider bool @[json: prepareProvider]\n}\n\n// method: ‘textDocument/rename’\n// response: WorkspaceEdit | none\npub struct RenameParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n\tnew_name      string @[json: newName]\n}\n\npub struct RenameRegistrationOptions {\npub:\n\tdocument_selector []DocumentFilter @[json: documentSelector]\n\tprepare_provider  bool             @[json: prepareProvider]\n}\n\n// method: ‘textDocument/prepareRename’\n// response: Range | { range: Range, placeholder: string } | none\n// request: TextDocumentPositionParams\n\npub struct PrepareRenameParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n}\n\npub struct PrepareRenameResult {\npub:\n\trange       Range\n\tplaceholder string\n}\n"
  },
  {
    "path": "src/lsp/semantic_tokens.v",
    "content": "module lsp\n\npub struct SemanticTokens {\npub:\n\t// An optional result id. If provided and clients support delta updating\n\t// the client will include the result id in the next semantic token request.\n\t// A server can then instead of computing all semantic tokens again simply\n\t// send a delta.\n\tresult_id string @[json: 'resultID']\n\t// The actual tokens.\n\tdata []u32\n}\n\npub struct SemanticTokensOptions {\npub:\n\t// The legend used by the server\n\tlegend SemanticTokensLegend\n\t// Server supports providing semantic tokens for a specific range\n\t// of a document.\n\trange bool @[omitempty]\n\t// Server supports providing semantic tokens for a full document.\n\tfull bool @[omitempty]\n}\n\npub struct SemanticTokensLegend {\npub:\n\t// The token types a server uses.\n\ttoken_types []string @[json: 'tokenTypes']\n\t// The token modifiers a server uses.\n\ttoken_modifiers []string @[json: 'tokenModifiers']\n}\n\npub struct SemanticTokensParams {\npub:\n\t// The text document.\n\ttext_document TextDocumentIdentifier @[json: 'textDocument']\n}\n\npub struct SemanticTokensRangeParams {\npub:\n\t// The text document.\n\ttext_document TextDocumentIdentifier @[json: 'textDocument']\n\t// The range the semantic tokens are requested for.\n\trange Range @[omitempty]\n}\n"
  },
  {
    "path": "src/lsp/signature_help.v",
    "content": "module lsp\n\npub struct SignatureHelpOptions {\npub:\n\ttrigger_characters   []string @[json: triggerCharacters]\n\tretrigger_characters []string @[json: retriggerCharacters]\n}\n\n@[json_as_number]\npub enum SignatureHelpTriggerKind {\n\tinvoked           = 1\n\ttrigger_character = 2\n\tcontent_change    = 3\n}\n\n// method: ‘textDocument/signatureHelp’\n// response: SignatureHelp | none\npub struct SignatureHelpParams {\npub:\n\t// TODO: utilize struct embedding feature\n\t// for all structs that use TextDocumentPositionParams\n\t// embed: TextDocumentPositionParams\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n\tcontext       SignatureHelpContext\n}\n\npub struct SignatureHelpContext {\npub:\n\ttrigger_kind          SignatureHelpTriggerKind @[json: triggerKind]\n\ttrigger_character     string                   @[json: triggerCharacter]\n\tis_retrigger          bool                     @[json: isRetrigger]\n\tactive_signature_help SignatureHelp            @[json: activeSignatureHelp]\n}\n\npub struct SignatureHelp {\npub:\n\tsignatures []SignatureInformation\npub mut:\n\tactive_parameter int @[json: activeParameter]\n}\n\npub struct SignatureInformation {\npub mut:\n\tlabel string\n\t// documentation MarkupContent\n\tparameters []ParameterInformation\n}\n\npub struct ParameterInformation {\npub:\n\tlabel string\n}\n\npub struct SignatureHelpRegistrationOptions {\n\tdocument_selector  []DocumentFilter @[json: documentSelector]\n\ttrigger_characters []string         @[json: triggerCharacters]\n}\n"
  },
  {
    "path": "src/lsp/symbol.v",
    "content": "module lsp\n\n// method: ‘textDocument/signatureHelp’\n// response: SignatureHelp | none\n// request: TextDocumentPositionParams\n// struct SymbolInformation {\n// }\n"
  },
  {
    "path": "src/lsp/text_document.v",
    "content": "module lsp\n\npub struct Position {\npub:\n\tline      int\n\tcharacter int\n}\n\npub struct Range {\npub:\n\tstart Position\n\tend   Position\n}\n\npub fn (r Range) is_empty() bool {\n\treturn r.start.line == 0 && r.end.line == 0 && r.start.character == 0 && r.end.character == 0\n}\n\npub struct TextEdit {\npub:\n\trange    Range\n\tnew_text string @[json: 'newText']\n}\n\npub struct TextDocumentIdentifier {\npub:\n\turi DocumentUri\n}\n\npub struct TextDocumentEdit {\n\ttext_document VersionedTextDocumentIdentifier @[json: textDocument]\n\tedits         []TextEdit\n}\n\npub struct TextDocumentItem {\npub:\n\turi         DocumentUri\n\tlanguage_id string @[json: languageId]\n\tversion     int\n\ttext        string\n}\n\npub struct VersionedTextDocumentIdentifier {\npub:\n\turi     DocumentUri\n\tversion int\n}\n\npub struct Location {\npub mut:\n\turi   DocumentUri\n\trange Range\n}\n\npub struct LocationLink {\npub:\n\t// Span of the origin of this link.\n\t//\n\t// Used as the underlined span for mouse interaction. Defaults to the word\n\t// range at the mouse position.\n\torigin_selection_range Range @[json: 'originSelectionRange']\n\t// The target resource identifier of this link.\n\ttarget_uri DocumentUri @[json: 'targetUri']\n\t// The full target range of this link. If the target for example is a symbol\n\t// then target range is the range enclosing this symbol not including\n\t// leading/trailing whitespace but everything else like comments. This\n\t// information is typically used to highlight the range in the editor.\n\ttarget_range Range @[json: 'targetRange']\n\t// The range that should be selected and revealed when this link is being\n\t// followed, e.g the name of a function. Must be contained by the\n\t// `targetRange`. See also `DocumentSymbol#range`\n\ttarget_selection_range Range @[json: 'targetSelectionRange']\n}\n\n// pub struct TextDocumentContentChangeEvent {\n// range Range\n// text string\n// }\npub struct TextDocumentPositionParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\tposition      Position\n}\n\npub const markup_kind_plaintext = 'plaintext'\npub const markup_kind_markdown = 'markdown'\n\npub struct MarkupContent {\npub:\n\tkind string\n\t// MarkupKind\n\tvalue string\n}\n\npub struct TextDocument {\n\turi         DocumentUri\n\tlanguage_id string\n\tversion     int\n\tline_count  int\n}\n\npub struct FullTextDocument {\n\turi          DocumentUri\n\tlanguage_id  string\n\tversion      int\n\tcontent      string\n\tline_offsets []int\n}\n"
  },
  {
    "path": "src/lsp/text_sync.v",
    "content": "module lsp\n\npub struct TextDocumentSyncOptions {\npub:\n\t// Open and close notifications are sent to the server. If omitted open\n\t// close notifications should not be sent.\n\topen_close bool @[json: 'openClose']\n\t// Change notifications are sent to the server. See\n\t// TextDocumentSyncKind.None, TextDocumentSyncKind.Full and\n\t// TextDocumentSyncKind.Incremental. If omitted it defaults to\n\t// TextDocumentSyncKind.None.\n\tchange TextDocumentSyncKind = TextDocumentSyncKind.full @[omitempty]\n\t// If present will save notifications are sent to the server. If omitted\n\t// the notification should not be sent.\n\twill_save bool @[json: 'willSave']\n\t// If present save notifications are sent to the server. If omitted the\n\t// notification should not be sent.\n\tsave SaveOptions\n}\n\npub struct SaveOptions {\n\tinclude_text bool @[json: 'includeText']\n}\n\n// method: ‘textDocument/didOpen’\n// notification\npub struct DidOpenTextDocumentParams {\npub:\n\ttext_document TextDocumentItem @[json: textDocument]\n}\n\n// method: ‘textDocument/didChange’\n// notification\npub struct DidChangeTextDocumentParams {\npub:\n\t// The document that did change. The version number points\n\t// to the version after all provided content changes have\n\t// been applied.\n\ttext_document VersionedTextDocumentIdentifier @[json: textDocument]\n\t// The actual content changes. The content changes describe single state\n\t// changes to the document. So if there are two content changes c1 (at\n\t// array index 0) and c2 (at array index 1) for a document in state S then\n\t// c1 moves the document from S to S' and c2 from S' to S''. So c1 is\n\t// computed on the state S and c2 is computed on the state S'.\n\t//\n\t// To mirror the content of a document using change events use the following\n\t// approach:\n\t// - start with the same initial content\n\t// - apply the 'textDocument/didChange' notifications in the order you\n\t//   receive them.\n\t// - apply the `TextDocumentContentChangeEvent`s in a single notification\n\t//   in the order you receive them.\n\tcontent_changes []TextDocumentContentChangeEvent @[json: contentChanges]\n}\n\npub struct TextDocumentContentChangeEvent {\npub:\n\t// The range of the document that changed.\n\trange Range\n\t// The optional length of the range that got replaced.\n\trange_length int @[deprecated: 'use range instead'; json: 'rangeLength']\n\t// The new text for the provided range or the entire document.\n\ttext string\n}\n\npub struct TextDocumentChangeRegistrationOptions {\n\tdocument_selector []DocumentFilter @[json: documentSelector]\n\tsync_kind         int              @[json: syncKind]\n}\n\n// method: ‘textDocument/willSave’\n// notification\npub struct WillSaveTextDocumentParams {\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\treason        TextDocumentSaveReason\n}\n\n@[json_as_number]\npub enum TextDocumentSaveReason {\n\tmanual      = 1\n\tafter_delay = 2\n\tfocus_out   = 3\n}\n\n// ‘textDocument/willSaveWaitUntil’\n// response: []TextEdit | null\n// request: WillSaveTextDocumentParams\n// method: ‘textDocument/didSave’\n// notification\npub struct DidSaveTextDocumentParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n\ttext          string\n}\n\n// method: ‘textDocument/didClose’\n// notification\npub struct DidCloseTextDocumentParams {\npub:\n\ttext_document TextDocumentIdentifier @[json: textDocument]\n}\n"
  },
  {
    "path": "src/lsp/window.v",
    "content": "module lsp\n\n// method: ‘window/showMessage’\n// notification\npub struct ShowMessageParams {\npub:\n\t@type MessageType\n\t// @type int\n\tmessage string\n}\n\n@[json_as_number]\npub enum MessageType {\n\terror   = 1\n\twarning = 2\n\tinfo    = 3\n\tlog     = 4\n}\n\n// method: ‘window/showMessageRequest’\n// response: MessageActionItem | none / null\npub struct ShowMessageRequestParams {\npub:\n\t@type   MessageType\n\tmessage string\n\tactions []MessageActionItem\n}\n\npub struct MessageActionItem {\n\ttitle string\n}\n\n// method: ‘window/logMessage’\n// notification\npub struct LogMessageParams {\npub:\n\t@type   MessageType\n\tmessage string\n}\n\n// method: ‘telemetry/event\n// notification\n// any\n"
  },
  {
    "path": "src/lsp/workspace.v",
    "content": "module lsp\n\npub struct WorkspaceFolder {\n\turi  DocumentUri\n\tname string\n}\n\npub type ChangeAnnotationIdentifier = string\n\n// A workspace edit represents changes to many resources managed in the workspace. The edit\n// should either provide `changes` or `documentChanges`. If documentChanges are present\n// they are preferred over `changes` if the client can handle versioned document edits.\n//\n// Since version 3.13.0 a workspace edit can contain resource operations as well. If resource\n// operations are present clients need to execute the operations in the order in which they\n// are provided. So a workspace edit for example can consist of the following two changes:\n// (1) a create file a.txt and (2) a text document edit which insert text into file a.txt.\n//\n// An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will\n// cause failure of the operation. How the client recovers from the failure is described by\n// the client capability: `workspace.workspaceEdit.failureHandling`\npub struct WorkspaceEdit {\npub:\n\t// Holds changes to existing resources.\n\tchanges map[string][]TextEdit @[json: 'changes'; omitempty]\n\t// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes\n\t// are either an array of `TextDocumentEdit`s to express changes to n different text documents\n\t// where each text document edit addresses a specific version of a text document. Or it can contain\n\t// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations.\n\t//\n\t// Whether a client supports versioned document edits is expressed via\n\t// `workspace.workspaceEdit.documentChanges` client capability.\n\t//\n\t// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then\n\t// only plain `TextEdit`s using the `changes` property are supported.\n\tdocument_changes []TextDocumentEdit @[json: 'documentChanges'; omitempty]\n\t// A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and\n\t// delete file / folder operations.\n\t//\n\t// Whether clients honor this property depends on the client capability `workspace.changeAnnotationSupport`.\n\t//\n\t// @since 3.16.0\n\tchange_annotations map[string]ChangeAnnotation @[json: 'changeAnnotations'; omitempty]\n}\n\npub struct ChangeAnnotation { // line 6831\n\t// A human-readable string describing the actual change. The string\n\t// is rendered prominent in the user interface.\n\tlabel string @[omitempty]\n\t// A flag which indicates that user confirmation is needed\n\t// before applying the change.\n\tneeds_confirmation bool @[json: 'needsConfirmation'; omitempty]\n\t// A human-readable string which is rendered less prominent in\n\t// the user interface.\n\tdescription string @[omitempty]\n}\n\npub struct WorkspaceSymbol {\npub mut:\n\t// The name of this symbol. Will be displayed in the user interface and\n\t// therefore must not be an empty string or a string only consisting of\n\t// white spaces.\n\tname string\n\t// The kind of this symbol.\n\tkind SymbolKind\n\t// The name of the symbol containing this symbol. This information is for\n\t// user interface purposes (e.g. to render a qualifier in the user interface\n\t// if necessary). It can't be used to re-infer a hierarchy for the document\n\t// symbols.\n\tcontainer_name string @[json: 'containerName'; omitempty]\n\t// The location of this symbol. Whether a server is allowed to\n\t// return a location without a range depends on the client\n\t// capability `workspace.symbol.resolveSupport`.\n\t//\n\t// See also `SymbolInformation.location`.\n\tlocation Location @[omitempty]\n\t// A data entry field that is preserved on a workspace symbol between a\n\t// workspace symbol request and a workspace symbol resolve request.\n\tdata string @[raw]\n}\n\npub struct DidChangeWorkspaceFoldersParams {\n\tevent WorkspaceFoldersChangeEvent\n}\n\npub struct WorkspaceFoldersChangeEvent {\n\tadded   []WorkspaceFolder\n\tremoved []WorkspaceFolder\n}\n\n// method: ‘workspace/didChangeConfiguration’,\n// notification\npub struct DidChangeConfigurationParams {\n\tsettings string @[raw]\n}\n\n// method: ‘workspace/configuration’\n// response: []any / []string\npub struct ConfigurationParams {\n\titems []ConfigurationItem\n}\n\npub struct ConfigurationItem {\n\tscope_uri DocumentUri @[json: scopeUri]\n\tsection   string\n}\n\n// method: ‘workspace/didChangeWatchedFiles’\n// notification\npub struct DidChangeWatchedFilesParams {\npub:\n\tchanges []FileEvent\n}\n\npub struct FileEvent {\npub:\n\turi DocumentUri\n\ttyp FileChangeType @[json: 'type']\n}\n\n@[json_as_number]\npub enum FileChangeType {\n\tcreated = 1\n\tchanged = 2\n\tdeleted = 3\n}\n\npub struct DidChangeWatchedFilesRegistrationOptions {\n\twatchers []FileSystemWatcher\n}\n\n// The  glob pattern to watch.\n// Glob patterns can have the following syntax:\n// - `*` to match one or more characters in a path segment\n// - `?` to match on one character in a path segment\n// - `**` to match any number of path segments, including none\n// - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)\n// - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)\n// - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)\npub struct FileSystemWatcher {\n\tglob_pattern string @[json: globPattern]\n\tkind         int\n}\n\n@[json_as_number]\npub enum WatchKind {\n\tcreate = 1\n\tchange = 2\n\tdelete = 3\n}\n\n// method: ‘workspace/symbol’\n// response: []SymbolInformation | null\npub struct WorkspaceSymbolParams {\n\tquery string\n}\n\n// method: ‘workspace/executeCommand’\n// response: any | null\npub struct ExecuteCommandParams {\npub:\n\t// The identifier of the actual command handler.\n\tcommand string\n\t// Arguments that the command should be invoked with.\n\targuments string @[raw]\n}\n\npub struct ExecuteCommandRegistrationOptions {\n\tcommand []string\n}\n\n// method: ‘workspace/applyEdit’\n// response: ApplyWorkspaceEditResponse\n//\npub struct ApplyWorkspaceEditParams {\npub:\n\t// An optional label of the workspace edit. This label is\n\t// presented in the user interface for example on an undo\n\t// stack to undo the workspace edit.\n\tlabel string @[omitempty]\n\t// The edits to apply.\n\tedit WorkspaceEdit\n}\n\npub struct ApplyWorkspaceEditResponse {\n\tapplied        bool\n\tfailure_reason string @[json: failureReason]\n}\n"
  },
  {
    "path": "src/main.v",
    "content": "module main\n\nimport os\nimport cli\nimport time\nimport term\nimport config\nimport loglib\nimport server\nimport jsonrpc\nimport streams\nimport analyzer\nimport lsp.log\nimport metadata\n\n// default_tcp_port is default TCP port that the analyzer uses to connect to the socket\n// when the --socket flag is passed at startup.\n// See also the `--port` flag to specify a custom port.\nconst default_tcp_port = 5007\n\nfn run(cmd cli.Command) ! {\n\tstdio := cmd.flags.get_bool('stdio') or { true }\n\tsocket := cmd.flags.get_bool('socket') or { false }\n\tport := cmd.flags.get_int('port') or { default_tcp_port }\n\tuse_stdout_for_logs := cmd.flags.get_bool('log-to-stdout') or { false }\n\n\tif !socket && use_stdout_for_logs {\n\t\terrorln('Cannot use ${term.bold('--log-to-stdout')} flag without ${term.bold('--socket')} flag')\n\t\treturn\n\t}\n\n\tmut stream := if socket {\n\t\tstreams.new_socket_stream_server(port, true) or {\n\t\t\terrorln('Cannot use ${port} port for socket communication, try specify another port with --port')\n\t\t\treturn\n\t\t}\n\t} else if stdio {\n\t\tstreams.new_stdio_stream()\n\t} else {\n\t\terrorln('Either --stdio or --socket flag must be specified')\n\t\treturn\n\t}\n\n\tsetup_logger(!use_stdout_for_logs)\n\n\tmut ls := server.LanguageServer.new(analyzer.IndexingManager.new())\n\tmut jrpc_server := &jsonrpc.Server{\n\t\tstream:  stream\n\t\thandler: ls\n\t}\n\tmut lr := log.LogRecorder{}\n\tlr.enable()\n\tjrpc_server.interceptors = [&lr]\n\n\tdefer {\n\t\tmut out := loglib.get_output()\n\t\tif mut out is os.File {\n\t\t\tout.close()\n\t\t}\n\t}\n\n\tjrpc_server.start()\n}\n\nfn setup_logger(to_file bool) {\n\tif to_file {\n\t\tif !os.exists(config.analyzer_logs_path) {\n\t\t\tos.mkdir_all(config.analyzer_logs_path) or {\n\t\t\t\terrorln('Failed to create analyzer logs directory: ${err}')\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tconfig_path := os.join_path(config.analyzer_logs_path, config.analyzer_log_file_name)\n\n\t\tif mut file := os.open_file(config_path, 'a') {\n\t\t\tloglib.set_output(file)\n\t\t}\n\t}\n\n\tloglib.set_level(.trace)\n\tloglib.set_flush_rate(1 * time.second)\n}\n\nfn main() {\n\tmut cmd := cli.Command{\n\t\tname:        metadata.manifest.name\n\t\tversion:     metadata.full_version\n\t\tdescription: metadata.manifest.description\n\t\texecute:     run\n\t\tposix_mode:  true\n\t}\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'init'\n\t\tdescription: 'Initialize a configuration file inside the current directory.'\n\t\texecute:     init_cmd\n\t})\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'clear-cache'\n\t\tdescription: 'Clears the analyzer cache.'\n\t\texecute:     clear_cache_cmd\n\t})\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'up'\n\t\tdescription: 'Updates the analyzer to the latest version.'\n\t\texecute:     up_cmd\n\t\tposix_mode:  true\n\t\tflags:       [\n\t\t\tcli.Flag{\n\t\t\t\tflag:        .bool\n\t\t\t\tname:        'nightly'\n\t\t\t\tdescription: 'Install the latest nightly build'\n\t\t\t},\n\t\t]\n\t})\n\n\tcmd.add_command(cli.Command{\n\t\tname:        'check-updates'\n\t\tdescription: 'Checks for v-analyzer updates.'\n\t\texecute:     check_updates_cmd\n\t\tposix_mode:  true\n\t\tversion:     metadata.full_version\n\t})\n\n\tcmd.add_flags([\n\t\tcli.Flag{\n\t\t\tflag:          .bool\n\t\t\tname:          'stdio'\n\t\t\tdescription:   'Use stdio for communication.'\n\t\t\tdefault_value: [\n\t\t\t\t'true',\n\t\t\t]\n\t\t},\n\t\tcli.Flag{\n\t\t\tflag:        .bool\n\t\t\tname:        'socket'\n\t\t\tdescription: 'Use TCP connection for communication.'\n\t\t},\n\t\tcli.Flag{\n\t\t\tflag:        .bool\n\t\t\tname:        'log-to-stdout'\n\t\t\tdescription: 'Use stdout for logs, can be used only with --socket flag (Only for debug purposes).'\n\t\t},\n\t\tcli.Flag{\n\t\t\tflag:          .int\n\t\t\tname:          'port'\n\t\t\tdescription:   'Port to use for socket communication. (Default: 5007)'\n\t\t\tdefault_value: [\n\t\t\t\t'${default_tcp_port}',\n\t\t\t]\n\t\t},\n\t])\n\n\tcmd.parse(os.args)\n}\n"
  },
  {
    "path": "src/metadata/metadata.v",
    "content": "module metadata\n\nimport os\nimport v.vmod\nimport v.embed_file\n\npub const manifest = vmod.decode(@VMOD_FILE) or { panic(err) }\npub const build_datetime = $env('BUILD_DATETIME')\npub const build_commit = $env('BUILD_COMMIT')\npub const full_version = manifest.version + '.' + build_commit\n\nstruct EmbedFS {\npub mut:\n\tfiles []embed_file.EmbedFileData\n}\n\npub fn (e &EmbedFS) unpack_to(path string) ! {\n\tfor file in e.files {\n\t\tnew_path := os.norm_path(os.join_path(path, file.path))\n\t\tdir := os.dir(new_path)\n\t\tif !os.exists(dir) {\n\t\t\tos.mkdir_all(dir) or { return error('failed to create directory ${dir}') }\n\t\t}\n\t\tos.write_file(new_path, file.to_string())!\n\t}\n}\n\npub fn embed_fs() EmbedFS {\n\tmut files := []embed_file.EmbedFileData{}\n\tfiles << $embed_file('stubs/arrays.v', .zlib)\n\tfiles << $embed_file('stubs/primitives.v', .zlib)\n\tfiles << $embed_file('stubs/vweb.v', .zlib)\n\tfiles << $embed_file('stubs/compile_time_constants.v', .zlib)\n\tfiles << $embed_file('stubs/compile_time_reflection.v', .zlib)\n\tfiles << $embed_file('stubs/builtin_compile_time.v', .zlib)\n\tfiles << $embed_file('stubs/channels.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Deprecated.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Table.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Attribute.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/DeprecatedAfter.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Unsafe.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Flag.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Noreturn.v', .zlib)\n\tfiles << $embed_file('stubs/attributes/Manualfree.v', .zlib)\n\tfiles << $embed_file('stubs/implicit.v', .zlib)\n\tfiles << $embed_file('stubs/compile_time.v', .zlib)\n\tfiles << $embed_file('stubs/c_decl.v', .zlib)\n\tfiles << $embed_file('stubs/errors.v', .zlib)\n\tfiles << $embed_file('stubs/threads.v', .zlib)\n\n\treturn EmbedFS{\n\t\tfiles: files\n\t}\n}\n"
  },
  {
    "path": "src/metadata/stubs/README.md",
    "content": "## Description:\n\nThe `stubs` module contains files describing some features of the V language that are not explicitly\ndescribed in the standard library.\n\nFor example, some compile-time functions or attributes.\n\n> **Note**\n> This is not real code, it is only needed for Doki and IDE to be able to show documentation and\n> jump to definitions.\n"
  },
  {
    "path": "src/metadata/stubs/arrays.v",
    "content": "module stubs\n\n// element_type is the type of the elements in the array.\ntype element_type = any\n\n// ArrayInit describes an array initializer.\n// Example:\n// ```\n// arr := []int{}\n// arr_with_len := []int{len: 1} // [0]\n// arr_with_cap := []int{len: 1, cap: 100} // [0]\n// arr_with_len_init := []int{len: 1, init: 1} [1]\n// arr_with_init := []int{len: 2, cap: 100, init: index * 2} [0, 2]\n// ```\n//\n// Array initializer can contain three **optional** fields:\n// 1. `len` – length – number of pre-allocated and initialized elements in the array\n// 2. `cap` – capacity – amount of memory space which has been reserved for elements,\n//            but not initialized or counted as elements\n// 3. `init` – default initializer for each element\n//\n// All three fields can be used independently of the others.\n//\n// # cap field\n//\n// If `cap` is not specified, it is set to `len`. `cap` cannot be smaller than `len`.\n// `cap` can be used for improving performance of array operations, since no reallocation will be needed.\n//\n// ```\n// arr := []int{len: 2}\n// arr << 100 // there will be a reallocation that will slow down the program a bit\n//\n// arr_with_cap := []int{len: 2, cap: 10}\n// arr_with_cap << 100 // no reallocation\n// ```\n//\n// # init field\n//\n// If `init` is not specified, it is set to `0` for numerical type, `''` for string, etc.\n//\n// ```\n// arr := []int{len: 2}\n// assert arr == [0, 0]\n// ```\n//\n// In `init` field, you can use special `index` variable to refer to the current index.\n//\n// ```\n// arr := []int{len: 3, init: index * 2}\n// assert arr == [0, 2, 4]\n// ```\npub struct ArrayInit {\n\t// index represent the current element index that is being initialized inside `init`.\n\t//\n\t// **Example**\n\t// ```\n\t// arr := []int{len: 3, init: index * 2}\n\t// assert arr == [0, 2, 4]\n\t// ```\n\tindex int\npub:\n\t// len field represent number of pre-allocated and initialized elements in the array.\n\t// By default it is set to `0` for numerical type, `''` for string, etc.\n\t//\n\t// **Example**\n\t// ```\n\t// arr := []int{len: 3}\n\t// assert arr.len == 3\n\t// assert arr[0] == 0\n\t// assert arr[1] == 0\n\t// assert arr[2] == 0\n\t// ```\n\tlen int\n\t// cap field represent amount of memory space which has been reserved for elements,\n\t// but not initialized or counted as elements\n\t//\n\t// If `cap` is not specified, it is set to `len`. `cap` cannot be smaller than `len`.\n\t// `cap` can be used for improving performance of array operations, since no reallocation will be needed.\n\t//\n\t// **Example**\n\t// ```\n\t// arr := []int{len: 2}\n\t// arr << 100 // there will be a reallocation that will slow down the program a bit\n\t// arr_with_cap := []int{len: 2, cap: 10}\n\t// arr_with_cap << 100 // no reallocation\n\t// ```\n\tcap int\n\t// init field represent default initializer for each element.\n\t//\n\t// In `init` field, you can use special `index` variable to refer to the current index.\n\t//\n\t// **Example**\n\t// ```\n\t// arr := []int{len: 3, init: index * 2}\n\t// assert arr == [0, 2, 4]\n\t// ```\n\t//\n\t// If `init` is not specified, it is set to `0` for numerical type, `''` for string, etc.\n\t//\n\t// **Example**\n\t// ```\n\t// arr := []int{len: 2}\n\t// assert arr == [0, 0]\n\t// ```\n\tinit element_type\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Attribute.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Note: this is not an official attribute syntax, V does not provide\n// any official way to define attributes. This is used only for\n// documentation purposes.\n\n// Target describes the possible places where the attribute is allowed.\nenum Target {\n\tfunction\n\tfield\n\tstruct_\n\tenum_\n\tconstant\n\ttype_alias\n}\n\n// Attribute is base interface that describes the\n// information and behavior of any attribute.\ninterface Attribute {\n\tname            string   // name of the attribute\n\twith_arg        bool     // whether the attribute has an argument\n\targ_is_optional bool     // if with_arg is true, this field is used to indicate whether the argument is optional\n\ttarget          []Target // places where the attribute is allowed\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Deprecated.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Deprecated attribute mark declaration as deprecated.\n// Only *direct* accesses to element in *other modules*, will produce deprecation notices/warnings.\n// Optionally, a message can be provided. Format of the message is as follows:\n//\n// ```\n// use <new element name> instead\n// use <new element name> instead: <additional message>\n// ```\n//\n// See also [deprecated_after](#DeprecatedAfter) attribute.\n//\n// Example:\n// ```\n// [deprecated: 'use foo() instead']\n// fn boo() {}\n// ```\n// ```\n// [deprecated: 'use foo() instead: boo() has some issues']\n// fn boo() {}\n// ```\n@[attribute]\npub struct Deprecated {\n\tname            string   = 'deprecated'\n\twith_arg        bool     = true\n\targ_is_optional bool     = true\n\ttarget          []Target = [Target.struct_, Target.function, Target.field, Target.constant,\n\t\tTarget.type_alias]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/DeprecatedAfter.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// DeprecatedAfter attribute specifies a date, after which the element will be\n// considered deprecated.\n//\n// Before that date, calls to the function (for example) will be compiler\n// notices – you will see them, but the compilation is not affected.\n//\n// After that date, calls will become warnings, so ordinary compiling will still\n// work, but compiling with `-prod` will not (all warnings are treated like errors with `-prod`).\n//\n// 6 months after the deprecation date, calls will be hard\n// compiler errors.\n//\n// Note: Must be used with `deprecated` attribute!\n//\n// See also [deprecated](#Deprecated) attribute.\n//\n// Example:\n// ```\n// [deprecated: 'use `foo` instead']\n// [deprecated_after: '2023-05-27']\n// fn boo() {}\n// ```\n@[attribute]\npub struct DeprecatedAfter {\n\tname            string = 'deprecated_after'\n\twith_arg        bool   = true\n\targ_is_optional bool\n\ttarget          []Target = [Target.struct_, Target.function, Target.field, Target.constant,\n\t\tTarget.type_alias]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Flag.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Flag attribute mark enum as bitfield.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n// ```\n//\n// Here, each subsequent element will increase the value of the previous one\n// by shifting to the left.\n//\n// For an enum with a flag attribute, the special methods `has()` and `all()` can be used.\n//\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   p := Permissions.read\n//   assert p.has(.read | .other) // test if *at least one* of the flags is set\n//\n//   p1 := Permissions.read | .write\n//   assert p1.has(.write)\n//   assert p1.all(.read | .write) // test if *all* of the flags is set\n// }\n// ```\n@[attribute]\npub struct Flag {\n\tname            string = 'flag'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.enum_]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Heap.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Heap attribute mark struct as always heap-allocated,\n// so any struct creation will happen on the heap.\n@[attribute]\npub struct Heap {\n\tname            string = 'heap'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.struct_]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Json.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Json attribute specifies a custom field name when marshaled to JSON.\n// This is useful when you need to use a field name that is not allowed in V.\n// For example, you need to specify a PascalCase name for a field, V does not\n// allow such a name for a field, in which case you can use the Json attribute.\n//\n// Example:\n// ```v\n// struct User {\n// \t first_name string [json: 'FirstName']\n// }\n@[attribute]\npub struct Json {\n\tname            string = 'json'\n\twith_arg        bool   = true\n\targ_is_optional bool\n\ttarget          []Target = [Target.field]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/JsonAsNumber.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// JsonAsNumber marks an enum.\n// The fields of such enum will be encoded in JSON as numbers, not as strings\n// with the field name.\n//\n// Example:\n//\n// ```\n// [json_as_number]\n// enum Color {\n//   red = 1\n//   green = 2\n// }\n//\n// struct MyStruct {\n//   color Color = .green\n// }\n//\n// // JSON representation of MyStruct:\n// // {\n// //   \"color\": 2\n// // }\n//\n// // JSON representation of MyStruct without the attribute:\n// // {\n// //   \"color\": \"green\"\n// // }\n// ```\n@[attribute]\npub struct JsonAsNumber {\n\tname            string = 'json_as_number'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.enum_]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Manualfree.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Manualfree attribute marks a function and the autofree engine\n// will not automatically clear the memory allocated in that function.\n//\n// You will need to free any memory allocated in this function yourself.\n@[attribute]\npub struct Manualfree {\n\tname            string = 'manualfree'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.function]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Noinit.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Noinit attribute mark struct.\n// Such structs cannot be created in other modules through initialization (`Foo{}`).\n// Instead, they must be initialized via a call to the constructor-like function, if any.\n//\n// This attribute is useful when you need to make sure that the structure is always created\n// correctly and that all required fields are set.\n@[attribute]\npub struct Noinit {\n\tname            string = 'noinit'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.struct_]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Noreturn.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Noreturn attribute marks a function as not return to its caller.\n//\n// Such functions can be used at the end of or blocks, just like\n// [`exit`](#exit) or [`panic`](#panic).\n//\n// Such functions can not have return types, and should end either in `for {}`, or\n// by calling other `[noreturn]` functions.\n//\n// Example:\n//\n// ```\n// [noreturn]\n// fn redirect() {\n//    // do something\n//    exit(1)\n// }\n//\n// fn main() {\n//     if condition {\n//         redirect();\n//         // unreachable\n//     }\n// }\n// ```\n@[attribute]\npub struct Noreturn {\n\tname            string = 'noreturn'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.function]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Omitempty.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Omitempty attribute marks field as omitempty.\n// When field is omitempty, it will be omitted when marshaling to JSON if its value is empty.\n@[attribute]\npub struct Omitempty {\n\tname            string = 'omitempty'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.field]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Table.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Table attribute sets a custom table name (case-sensitive).\n// By default ORM uses default struct name.\n@[attribute]\npub struct Table {\n\tname            string = 'table'\n\twith_arg        bool   = true\n\targ_is_optional bool\n\ttarget          []Target = [Target.struct_]\n}\n"
  },
  {
    "path": "src/metadata/stubs/attributes/Unsafe.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule attributes\n\n// Unsafe attribute mark the function as unsafe, so\n// function can be called only from unsafe code.\n//\n// Example:\n// ```\n// [unsafe]\n// fn foo() {}\n//\n// fn main() {\n//   foo() // warning: function `foo` must be called from an `unsafe` block\n//\n//   unsafe {\n//     foo() // ok\n//   }\n// }\n// ```\n@[attribute]\npub struct Unsafe {\n\tname            string = 'unsafe'\n\twith_arg        bool\n\targ_is_optional bool\n\ttarget          []Target = [Target.function]\n}\n"
  },
  {
    "path": "src/metadata/stubs/builtin_compile_time.v",
    "content": "module stubs\n\ntype placeholder = any\n\n// TypeInfo describe type information returned by the [typeof](#$typeof) builtin function.\npub struct TypeInfo {\npub mut:\n\tidx  int    // index of the type in the type table\n\tname string // name of the type\n}\n\n// $offsetof returns the offset of the field with passed name in the passed struct.\n//\n// Example:\n// ```\n// struct Foo {\n//    a int\n//    b string\n// }\n//\n// assert __offsetof(Foo, b) == 8\n// ```\npub fn $offsetof(struct_type placeholder, field_name placeholder) int\n\n// $isreftype returns true if the type is a reference type.\n//\n// This builtin function can be used in two ways:\n// 1. `isreftype[type]()` – check passed type\n// 2. `isreftype(expr)` – check type of passed expression\n//\n// Examples:\n// ```\n// assert isreftype[int]() == false\n// assert isreftype[string]() == true\n// assert isreftype[[]int]() == true\n// assert isreftype[map[string]int]() == true\n// assert isreftype('hello') == true\n// assert isreftype(10) == true\n// ```\npub fn $isreftype[T](typ T) bool\n\n// $sizeof returns the size of a type in bytes.\n//\n// This builtin function can be used in two ways:\n//\n// 1. `sizeof[type]()` – returns the size of the type in bytes\n// 2. `sizeof(expr)` – returns the size of the type of the expression in bytes\n//\n// The size of a type is the number of bytes it occupies in memory.\n//\n// Example:\n// ```\n// assert sizeof[i64]() == 8\n// assert sizeof[[]int]() == 32\n// assert sizeof('hello') == 16\n// assert sizeof(i64(100)) == 8\n// assert sizeof(true) == 1\n// ```\npub fn $sizeof[T](typ T) int\n\n// $typeof returns the [TypeInfo](#TypeInfo) of the given expression.\n//\n// Example:\n// ```\n// type StringOrInt = string | int\n//\n// fn foo(x StringOrInt) {\n//   if typeof(x).name == 'string' {\n//     println('x is a string')\n//   }\n// }\n//\npub fn $typeof[T](typ T) TypeInfo\n\n// $dump prints the given expression with position of `dump()` call.\n//\n// Example:\n// ```\n// name := 'John'\n// dump(name)\n// ```\n// Output:\n// ```\n// [/Users/petrmakhnev/intellij-v/main.v:2] name: John\n// ```\npub fn $dump[T](typ T) T\n"
  },
  {
    "path": "src/metadata/stubs/c_decl.v",
    "content": "module stubs\n\npub struct UnknownCDeclaration {\npub mut:\n\tunknown_field &UnknownCDeclaration\n}\n\npub fn (c &UnknownCDeclaration) unknown_method(...any) any\n"
  },
  {
    "path": "src/metadata/stubs/channels.v",
    "content": "module stubs\n\n// `chan` keyword defines a typed channel that is used for communication between\n// several threads in multithreaded programs.\n//\n// Channels are a typed conduit through which you can send and receive values\n// with the channel (`<-`) operator.\n//\n// ```\n// ch := chan int{} // channel of ints\n// ch2 := chan f64{} // channel of f64s\n// ```\n//\n// Values can be sent to a channel using the arrow operator <-:\n//\n// ```\n// ch <- 5\n// ```\n//\n// Or obtained from a channel:\n//\n// ```\n// i := <-ch\n// ```\n//\n// Learn more about channels in the [documentation](https://docs.vosca.dev/concepts/concurrency/channels.html).\npub struct ChanInit {\npub:\n\t// cap fields describes the size of the buffered channel.\n\t//\n\t// The channel size describes the number of elements that can be\n\t// written to the channel without blocking.\n\t// If more elements are written to the channel than the buffer size,\n\t// then the write is blocked until another thread reads the element\n\t// from the channel and there is free space.\n\t//\n\t// If `cap == 0` (default), then the channel is not buffered.\n\t//\n\t// **Example**\n\t// ```\n\t// ch := chan int{cap: 10} // buffered channel\n\t// ch <- 1 // no blocking\n\t// ```\n\t//\n\t// **Example**\n\t// ```\n\t// ch := chan int{} // unbuffered channel\n\t// ch <- 1 // block until another thread reads from the channel\n\t// ```\n\tcap int\n}\n"
  },
  {
    "path": "src/metadata/stubs/compile_time.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// This file contains definitions of compile time functions and constants.\n\nimport v.embed_file { EmbedFileData }\n\n// @FN replaced with the name of the current V function.\npub const @FN = ''\n\n// @METHOD replaced with name of the current V method and receiver type: `ReceiverType.MethodName`.\npub const @METHOD = ''\n\n// @MOD replaced with the name of the current V module.\npub const @MOD = ''\n\n// @STRUCT  replaced with the name of the current V struct.\npub const @STRUCT = ''\n\n// @FILE replaced with the absolute path of the V source file.\npub const @FILE = ''\n\n// @LINE replaced with the V line number where it appears (as a string).\npub const @LINE = ''\n\n// @FILE_LINE replaced with `@FILE:@LINE`, but the file part is a relative path.\npub const @FILE_LINE = ''\n\n// @COLUMN replaced with the column where it appears (as a string).\npub const @COLUMN = ''\n\n// @VEXE replaced with the path to the V compiler.\npub const @VEXE = ''\n\n// @VEXEROOT replaced with the folder, where the V executable is.\npub const @VEXEROOT = ''\n\n// @VHASH replaced with the shortened commit hash of the V compiler.\npub const @VHASH = ''\n\n// @VMOD_FILE replaced with the contents of the nearest v.mod file.\npub const @VMOD_FILE = ''\n\n// @VMODROOT replaced with the folder, where the nearest v.mod file is.\npub const @VMODROOT = ''\n\n// CompressionType is the type of compression used for the embedded file.\n// See [$embed_file] for more details.\npub enum CompressionType {\n\tzlib\n}\n\n// $embed_file embed a file in a binary.\n//\n// Passed file path can be absolute or relative.\n//\n// When the program is compiled without the `-prod` flag, the file will not be embedded. Instead,\n// it will be loaded the first time your program calls\n//\n//\n// When you compile with -prod, the file will be embedded inside your executable,\n// increasing your binary size, but making it more self contained and thus easier\n// to distribute.\n// In this case, `embedded_file.data()` will cause no IO, and it will always return the same data.\n//\n// `$embed_file` supports compression of the embedded file when compiling with `-prod`.\n// Currently only one compression type is supported: `zlib`. See [CompressionType](CompressionType) for more details.\n//\n// Example:\n// ```\n// embedded_file := $embed_file('v.png', .zlib) // compressed using zlib\n// data := embedded_file.data() // get data as a u8 array\n// path := embedded_file.path // get path to the file\n// ```\npub fn $embed_file(path string, compression_type CompressionType) EmbedFileData\n\n// $tmpl embed and parse template file.\n//\n// Passed file path can be absolute or relative.\n//\n// `$tmpl` compiles an template into V during compilation, and embeds the resulting\n// code into the current function. That means that the template automatically has\n// access to that function's entire environment (like variables).\n//\n// See [Template documentation](https://docs.vosca.dev/concepts/templates/overview.html) for more details.\n//\n// Example:\n// ```\n// fn build() string {\n//   name := 'Peter'\n//   age := 25\n//   numbers := [1, 2, 3]\n//   return $tmpl('template.txt')\n// }\n// ```\npub fn $tmpl(path string) string\n\n// $env obtain the value of the environment variable with passed name at compile time.\n//\n// Example:\n// ```\n// println($env('HOME'))\n// ```\npub fn $env(name string) string\n\n// $compile_error causes a compile error with the passed message.\n//\n// Example:\n// ```\n// $if windows {\n//   $compile_error('Windows is not supported')\n// }\n// ```\n@[noreturn]\npub fn $compile_error(msg string)\n\n// $compile_warn causes a compile warning with the passed message.\n//\n// Example:\n// ```\n// $if windows {\n//   $compile_warn('Windows is not fully supported')\n// }\n// ```\npub fn $compile_warn(msg string)\n\n// _likely_ is a hint to the compiler that the passed expression is **likely to be true**,\n// so it can generate assembly code, with less chance of\n// [branch misprediction](https://en.wikipedia.org/wiki/Branch_predictor).\n//\n// Example:\n// ```\n// if _likely_(x > 0) {\n//   // code\n// }\n// ```\n//\n// In a non-C backend, it is ignored.\npub fn _likely_(typ bool) bool\n\n// _unlikely_ is a hint to the compiler that the passed expression is **highly improbable**.\n// See also [branch predictor](https://en.wikipedia.org/wiki/Branch_predictor).\n//\n// Example:\n// ```\n// if _unlikely_(x < 0) {\n//   // code\n// }\n// ```\n//\n// In a non-C backend, it is ignored.\npub fn _unlikely_(typ bool) bool\n"
  },
  {
    "path": "src/metadata/stubs/compile_time_constants.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// This file contains definitions of compile time constants used in $if.\n// Example:\n// ```v\n// $if linux {\n//   println('linux') // this will be printed only if the current OS is Linux\n// } $else $if windows {\n//   println('windows') // this will be printed only if the current OS is Windows\n// } $else {\n//   println('other') // this will be printed if the current OS is neither Linux nor Windows\n// }\n// ```\n\n// OSs\n\n// windows set to `true` if the current OS is Windows.\npub const windows = false\n\n// linux set to `true` if the current OS is Linux.\npub const linux = false\n\n// macos set to `true` if the current OS is macOS.\npub const macos = false\n\n// mac set to `true` if the current OS is macOS.\npub const mac = false\n\n// darwin set to `true` if the current OS is macOS.\npub const darwin = false\n\n// freebsd set to `true` if the current OS is FreeBSD.\npub const freebsd = false\n\n// openbsd set to `true` if the current OS is OpenBSD.\npub const openbsd = false\n\n// netbsd set to `true` if the current OS is NetBSD.\npub const netbsd = false\n\n// serenity set to `true` if the current OS is Serenity.\npub const serenity = false\n\n// vinix set to `true` if the current OS is Vinix.\npub const vinix = false\n\n// ios set to `true` if the current OS is iOS.\npub const ios = false\n\n// android set to `true` if the current OS is Android.\npub const android = false\n\n// emscripten set to `true` if the current OS is Emscripten.\npub const emscripten = false\n\n// js_node set to `true` if the current platform is Node.js.\npub const js_node = false\n\n// js_freestanding set to `true` if the current platform is pure JavaScript.\npub const js_freestanding = false\n\n// js_browser set to `true` if the current platform is JavaScript in a browser.\npub const js_browser = false\n\n// js set to `true` if the current platform is JavaScript.\npub const js = false\n\n// mach set to `true` if the current OS is Mach.\npub const mach = false\n\n// dragonfly set to `true` if the current OS is Dragonfly.\npub const dragonfly = false\n\n// gnu set to `true` if the current OS is GNU.\npub const gnu = false\n\n// hpux set to `true` if the current OS is HP-UX.\npub const hpux = false\n\n// haiku set to `true` if the current OS is Haiku.\npub const haiku = false\n\n// qnx set to `true` if the current OS is QNX.\npub const qnx = false\n\n// solaris set to `true` if the current OS is Solaris.\npub const solaris = false\n\n// termux set to `true` if the current OS is Termux.\npub const termux = false\n\n// Compilers\n\n// gcc set to `true` if the current compiler is GCC.\npub const gcc = false\n\n// tiny set to `true` if the current compiler is TinyCC.\npub const tiny = false\n\n// clang set to `true` if the current compiler is Clang.\npub const clang = false\n\n// mingw set to `true` if the current compiler is MinGW.\npub const mingw = false\n\n// msvc set to `true` if the current compiler is MSVC.\npub const msvc = false\n\n// cpp set to `true` if the current compiler is C++.\npub const cplusplus = false\n\n// Platforms\n\n// x86 set to `true` if the current platform is x86.\npub const amd64 = false\n\n// arm set to `true` if the current platform is ARM.\npub const arm64 = false\n\n// x64 set to `true` if the current platform is x64.\npub const x64 = false\n\n// x32 set to `true` if the current platform is x32.\npub const x32 = false\n\n// little_endian set to `true` if the current platform is little endian.\npub const little_endian = false\n\n// big_endian set to `true` if the current platform is big endian.\npub const big_endian = false\n\n// Other\n\n// debug set to `true` if the -g flag is passed to the compiler.\npub const debug = false\n\n// prod set to `true` if the -prod flag is passed to the compiler.\npub const prod = false\n\n// test set to `true` file run with `v test`.\npub const test = false\n\n// glibc set to `true` if the -glibc flag is passed to the compiler.\npub const glibc = false\n\n// prealloc set to `true` if the -prealloc flag is passed to the compiler.\npub const prealloc = false\n\n// no_bounds_checking set to `true` if the -no_bounds_checking flag is passed to the compiler.\npub const no_bounds_checking = false\n\n// freestanding set to `true` if the -freestanding flag is passed to the compiler.\npub const freestanding = false\n\n// no_segfault_handler set to `true` if the -no_segfault_handler flag is passed to the compiler.\npub const no_segfault_handler = false\n\n// no_backtrace set to `true` if the -no_backtrace flag is passed to the compiler.\npub const no_backtrace = false\n\n// no_main set to `true` if the -no_main flag is passed to the compiler.\npub const no_main = false\n"
  },
  {
    "path": "src/metadata/stubs/compile_time_reflection.v",
    "content": "// Copyright (c) 2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// This file contains definitions of compile time reflection.\n\n// $int describes any integer type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $int {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $int = TypeInfo{}\n\n// $float describes any float type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $float {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $float = TypeInfo{}\n\n// $array describes any array type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $array {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $array = TypeInfo{}\n\n// $map describes any map type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $map {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $map = TypeInfo{}\n\n// $struct describes any struct type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $struct {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $struct = TypeInfo{}\n\n// $interface describes any interface type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $interface {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $interface = TypeInfo{}\n\n// $enum describes any enum type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $enum {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $enum = TypeInfo{}\n\n// $alias describes any alias type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $alias {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $alias = TypeInfo{}\n\n// $sumtype describes any sumtype type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $sumtype {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $sumtype = TypeInfo{}\n\n// $function describes any function type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $function {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $function = TypeInfo{}\n\n// $option describes any option type.\n//\n// Example:\n// ```\n// $for f in Test.fields {\n//   $if f.typ is $option {\n//     println(f.name)\n//   }\n// }\n// ```\npub const $option = TypeInfo{}\n\nstruct CompileTimeTypeInfo {\npub:\n\t// fields describes the list of structure fields.\n\t// This field can only be used inside `$for`.\n\t//\n\t// Example:\n\t// ```v\n\t// struct Foo {\n\t//   a int\n\t//   b string\n\t// }\n\t//\n\t// fn main() {\n\t//   $for field in Foo.fields {\n\t//     println(field.name)\n\t//   }\n\t// }\n\t// ```\n\tfields []FieldData\n}\n"
  },
  {
    "path": "src/metadata/stubs/errors.v",
    "content": "module stubs\n\n// err is a special variable that is set with an error\n// and is used to handle errors in V.\n//\n// It can be used inside two places:\n//\n// 1. inside `or` block:\n// ```\n// fn foo() !int {\n//   return error(\"not implemented\");\n// }\n//\n// foo() or {\n//   panic(err);\n//   //    ^^^ err is set with error(\"not implemented\")\n// }\n// ```\n//\n// 2. inside else block for if guard:\n// ```\n// fn foo() !int {\n//   return error(\"not implemented\");\n// }\n//\n// if val := foo() {\n//   // val is set with int\n// } else {\n//   panic(err);\n//   //    ^^^ err is set with error(\"not implemented\")\n// }\n// ```\n//\n// See [Documentation](https://docs.vosca.dev/concepts/error-handling/overview.html)\n// for more details.\npub const err = IError{}\n"
  },
  {
    "path": "src/metadata/stubs/implicit.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// Any is any type in code.\n//\n// It is needed to define all implicit methods of all types.\ntype Any = any\n\n// str returns a string representation of the type.\n//\n// **Note**\n//\n// This method is implicitly implemented by any type,\n// you can override it for your type:\n// ```\n// struct MyStruct {\n//   name string\n// }\n//\n// pub fn (s MyStruct) str() string {\n//   return s.name\n// }\n// ```\n//\n// Example:\n//\n// ```\n// struct Foo {}\n//\n// fn main() {\n//   s := Foo{}\n//   println(s.str()) // Foo{}\n//\n//   mp := map[string]int{}\n//   println(mp.str()) // map[string]int{}\n// }\n// ```\npub fn (a Any) str() string\n\n// FlagEnum describes a enum with `[flag]` attribute.\n//\n// See [Flag](#flag) attribute for detail.\npub enum FlagEnum {}\n\n// has checks if the enum value has the passed flag.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   p := Permissions.read\n//   assert p.has(.read) // test if p has read flag\n//   assert p.has(.read | .other) // test if *at least one* of the flags is set\n// }\n// ```\npub fn (f FlagEnum) has(flag FlagEnum) bool\n\n// all checks if the enum value has all passed flags.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   p := Permissions.read | .write\n//   assert p.all(.read | .write) // test if *all* of the flags is set\n// }\n// ```\npub fn (f FlagEnum) all(flag FlagEnum) bool\n\n// set sets the passed flags.\n// If the flag is already set, it will be ignored.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   mut p := Permissions.read\n//   p.set(.write)\n//   assert p.has(.write)\n// }\n// ```\npub fn (f FlagEnum) set(flag FlagEnum)\n\n// toggle toggles the passed flags.\n// If the flag is already set, it will be unset.\n// If the flag is not set, it will be set.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   mut p := Permissions.read\n//   p.toggle(.read)\n//   assert !p.has(.read)\n// }\n// ```\npub fn (f FlagEnum) toggle(flag FlagEnum)\n\n// clear clears the passed flags.\n// If the flag is not set, it will be ignored.\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   mut p := Permissions.read\n//   p.clear(.read)\n//   assert !p.has(.read)\n// }\n// ```\npub fn (f FlagEnum) clear(flag FlagEnum)\n"
  },
  {
    "path": "src/metadata/stubs/primitives.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// This file contains definitions of primitive types V.\n\n// bool is the set of boolean values, true and false.\npub type bool = bool\n\n// u8 is the set of all unsigned 8-bit integers.\n// Range: 0 through 255.\npub type u8 = u8\n\n// u16 is the set of all unsigned 16-bit integers.\n// Range: 0 through 65535.\npub type u16 = u16\n\n// u32 is the set of all unsigned 32-bit integers.\n// Range: 0 through 4294967295.\npub type u32 = u32\n\n// u64 is the set of all unsigned 64-bit integers.\n// Range: 0 through 18446744073709551615.\npub type u64 = u64\n\n// usize is platform-dependent unsigned integer type.\npub type usize = u64\n\n// i8 is the set of all signed 8-bit integers.\n// Range: -128 through 127.\npub type i8 = i8\n\n// i16 is the set of all signed 16-bit integers.\n// Range: -32768 through 32767.\npub type i16 = i16\n\n// i32 is the set of all signed 32-bit integers.\n// Range: -2147483648 through 2147483647.\npub type i32 = int\n\n// int is the set of all signed 32-bit integers.\n// Range: -2147483648 through 2147483647.\npub type int = int\n\n// i64 is the set of all signed 64-bit integers.\n// Range: -9223372036854775808 through 9223372036854775807.\npub type i64 = i64\n\n// isize is a signed integer type, whose size varies, and is 32bit on 32bit platforms, or 64bit on 64bit platforms.\npub type isize = i64\n\n// usize is an unsigned integer type, whose size varies and is 32bit on 32bit platforms, or 64bit on 64bit platforms.\npub type usize = u64\n\n// f32 is the set of all IEEE-754 32-bit floating-point numbers.\npub type f32 = f32\n\n// f64 is the set of all IEEE-754 64-bit floating-point numbers.\npub type f64 = f64\n\n// byte is an alias for u8 and is equivalent to u8 in all ways.\n// Do not use `byte` in new code, use `u8` instead.\npub type byte = u8\n\n// rune is used, for representing individual Unicode codepoints. It is 32bit sized.\npub type rune = u32\n\n// char is similar to u8, it is mostly used for [C interoperability](https://docs.vosca.dev/advanced-concepts/v-and-c.html).\n// In C, the type `char` can be signed or unsigned, depending on platform.\npub type char = u8\n\n// voidptr is an untyped pointer. You can pass any other type of pointer value, to a function that accepts a voidptr.\n// Mostly used for [C interoperability](https://docs.vosca.dev/advanced-concepts/v-and-c.html).\npub type voidptr = voidptr\n\n// byteptr is a pointer to bytes. Deprecated. Use `&u8` instead in new code.\n// Mostly used for [C interoperability](https://docs.vosca.dev/advanced-concepts/v-and-c.html).\npub type byteptr = byteptr\n\n// charptr is a pointer to chars.\n// Mostly used for [C interoperability](https://docs.vosca.dev/advanced-concepts/v-and-c.html).\npub type charptr = charptr\n"
  },
  {
    "path": "src/metadata/stubs/threads.v",
    "content": "module stubs\n\n// Thread represent `thread T` type.\nstruct Thread[T] {}\n\n// wait waits for thread to finish and returns its result.\n//\n// It is a blocking call, and will block the current thread until the thread finishes.\n//\n// Return type is `T` where `T` is the type of the thread.\n// ```\n// int_thread := spawn fn () int { return 1 }()\n// //                        ^^^ return `int` type\n// int_thread.wait() // returns int\n//\n// arr_string_thread := spawn fn () []string { return ['Hello World'] }()\n// //                               ^^^^^^^^ return `[]string` type\n// arr_string_thread.wait() // returns []string\n// ```\n//\n// Example:\n// ```\n// fn expensive_computing(i int) int {\n//   return i * i\n// }\n//\n// fn main() {\n//   mut thread := spawn expensive_computing(100)\n//   //  ^^^^^^ has type `thread int`, because `expensive_computing()` returns `int`\n//   result := thread.wait()\n//\n//   println('Result: ${result}')\n//   // Output:\n//   // Result: 10000\n// }\n// ```\n//\npub fn (t Thread[T]) wait() T\n\n// ThreadPool represent a pool of threads: `[]thread T` type.\nstruct ThreadPool[T] {}\n\n// wait waits for all threads in the pool to finish\n// and returns result of all threads as array.\n//\n// It is a blocking call, and will not return until all threads are finished.\n//\n// Return type is `[]T` where `T` is the type of the thread.\n// ```\n// mut int_threads := []thread int{}\n// //                          ^^^\n// int_threads.wait() // returns []int\n//\n// mut arr_string_threads := []thread []string{}\n// //                                 ^^^^^^^^\n// arr_string_threads.wait() // returns [][]string\n// ```\n//\n// Example:\n// ```\n// fn expensive_computing(i int) int {\n//   return i * i\n// }\n//\n// fn main() {\n//   mut threads := []thread int{}\n//   for i in 1 .. 10 {\n//     threads << spawn expensive_computing(i)\n//   }\n//\n//   results := threads.wait()\n//   println('All jobs finished: ${results}')\n//\n//   // Output:\n//   // All jobs finished: [1, 4, 9, 16, 25, 36, 49, 64, 81]\n// }\n// ```\n//\n// See [Documentation](https://docs.vosca.dev/concepts/concurrency.html) for more details.\npub fn (t ThreadPool[T]) wait() []T\n"
  },
  {
    "path": "src/metadata/stubs/vweb.v",
    "content": "// Copyright (c) 2022-2023 Petr Makhnev. All rights reserved.\n// Use of this source code is governed by a MIT\n// license that can be found in the LICENSE file.\nmodule stubs\n\n// This file contains stubs for the vweb module.\n\nimport vweb\n\nstruct VWebTemplate {}\n\n// html method renders a template.\n// See documentation for [$vweb]($vweb) for more information.\npub fn (v VWebTemplate) html() vweb.Result\n\n// $vweb constant allows you to render HTML template in endpoint functions.\n//\n// `$vweb.html()` in method like `<folder>_<name>() vweb.Result`\n// render the `<name>.html` in folder `./templates/<folder>`\n//\n// `$vweb.html()` compiles an HTML template into V during compilation, and\n// embeds the resulting code into the current function.\n// That means that the template automatically has access to that\n// function's entire environment (like variables).\n//\n// See [vweb documentation](https://modules.vosca.dev/standard_library/vweb.html) for more information.\n//\n// Example:\n// ```\n// ['/']\n// pub fn (mut app App) page_home() vweb.Result {\n//   // will render `./templates/page/home.html`\n//   return $vweb.html()\n// }\n// ```\npub const $vweb = VWebTemplate{}\n"
  },
  {
    "path": "src/project/flavors/MacToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct MacToolchainFlavor {}\n\nfn (s &MacToolchainFlavor) get_home_page_candidates() []string {\n\treturn ['/usr/local/Cellar/v', '/usr/local/v', os.expand_tilde_to_home('~/v')]\n\t\t.filter(os.is_dir)\n}\n\nfn (s &MacToolchainFlavor) is_applicable() bool {\n\t$if macos {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/project/flavors/SymlinkToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct SymlinkToolchainFlavor {}\n\nfn (s &SymlinkToolchainFlavor) get_home_page_candidates() []string {\n\tsymlink_path_candidates := [\n\t\t'/usr/bin/v',\n\t\t'/usr/local/bin/v',\n\t\t'${os.home_dir()}/.local/bin/v',\n\t]\n\n\tmut result := []string{}\n\n\tfor symlink_path_candidate in symlink_path_candidates {\n\t\tpath_to_compiler := os.real_path(symlink_path_candidate)\n\t\tif path_to_compiler == '' {\n\t\t\tcontinue\n\t\t}\n\n\t\tcompiler_dir := os.dir(path_to_compiler)\n\t\tif os.is_dir(compiler_dir) {\n\t\t\tresult << compiler_dir\n\t\t}\n\t}\n\n\treturn result\n}\n\nfn (s &SymlinkToolchainFlavor) is_applicable() bool {\n\t$if linux || macos || openbsd || freebsd || netbsd {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/project/flavors/SysPathToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct SysPathToolchainFlavor {}\n\nfn (s &SysPathToolchainFlavor) get_home_page_candidates() []string {\n\treturn os.getenv('PATH')\n\t\t.split(os.path_delimiter)\n\t\t.filter(it != '')\n\t\t.filter(os.is_dir)\n\t\t.map(if os.file_name(it) == '.bin' {\n\t\t\tos.dir(it)\n\t\t} else {\n\t\t\tit\n\t\t})\n}\n\nfn (s &SysPathToolchainFlavor) is_applicable() bool {\n\treturn true\n}\n"
  },
  {
    "path": "src/project/flavors/ToolchainFlavor.v",
    "content": "module flavors\n\nimport arrays\nimport os\n\npub interface ToolchainFlavor {\n\tget_home_page_candidates() []string\n\tis_applicable() bool\n}\n\nfn is_valid_toolchain_path(path string) bool {\n\treturn os.is_dir(path) && has_executable(path, 'v') && has_vlib(path)\n}\n\nfn has_executable(path string, exe string) bool {\n\tmut with_exe := os.join_path(path, exe)\n\t$if windows {\n\t\twith_exe += '.exe'\n\t}\n\n\treturn os.is_executable(with_exe)\n}\n\nfn has_vlib(path string) bool {\n\tvlib_path := os.join_path(path, 'vlib')\n\treturn os.is_dir(vlib_path)\n}\n\npub fn get_toolchain_candidates() []string {\n\tmut flavors := []ToolchainFlavor{}\n\tflavors << VenvToolchainFlavor{}\n\t$if !windows {\n\t\t// On Windows, a symlink to V is not created, so it makes no sense to check this option.\n\t\tflavors << SymlinkToolchainFlavor{}\n\t}\n\tflavors << SysPathToolchainFlavor{}\n\tflavors << UserHomeToolchainFlavor{}\n\t$if macos {\n\t\tflavors << MacToolchainFlavor{}\n\t}\n\t$if windows {\n\t\tflavors << WinToolchainFlavor{}\n\t}\n\n\treturn arrays.flatten(flavors\n\t\t.filter(it.is_applicable())\n\t\t.map(it.get_home_page_candidates()))\n\t\t.filter(is_valid_toolchain_path)\n}\n"
  },
  {
    "path": "src/project/flavors/UserHomeToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct UserHomeToolchainFlavor {}\n\nfn (s &UserHomeToolchainFlavor) get_home_page_candidates() []string {\n\thome := os.home_dir()\n\tfiles := os.ls(home) or { return [] }\n\treturn files\n\t\t.filter(os.is_dir)\n\t\t.filter(fn (path string) bool {\n\t\t\tname := os.file_name(path).to_lower()\n\t\t\treturn name == 'v' || name == 'vlang'\n\t\t})\n}\n\nfn (s &UserHomeToolchainFlavor) is_applicable() bool {\n\treturn true\n}\n"
  },
  {
    "path": "src/project/flavors/VenvToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct VenvToolchainFlavor {}\n\nfn (s &VenvToolchainFlavor) get_home_page_candidates() []string {\n\tmut res := []string{}\n\tif vroot := os.getenv_opt('VROOT') {\n\t\tres << vroot\n\t}\n\tif vexe := os.getenv_opt('VEXE') {\n\t\tres << os.dir(vexe)\n\t}\n\treturn res.filter(os.is_dir)\n}\n\nfn (s &VenvToolchainFlavor) is_applicable() bool {\n\treturn true\n}\n"
  },
  {
    "path": "src/project/flavors/WinToolchainFlavor.v",
    "content": "module flavors\n\nimport os\n\npub struct WinToolchainFlavor {}\n\nfn (s &WinToolchainFlavor) get_home_page_candidates() []string {\n\tmut res := []string{}\n\tresult := os.execute('where v')\n\tif result.exit_code == 0 {\n\t\tres << os.dir(result.output.trim_space())\n\t}\n\n\tprogram_files := os.getenv('ProgramFiles')\n\tif !os.exists(program_files) || !os.is_dir(program_files) {\n\t\treturn res\n\t}\n\n\tif files := os.ls(program_files) {\n\t\tres << files\n\t\t\t.filter(os.is_dir)\n\t\t\t.filter(fn (path string) bool {\n\t\t\t\tname := os.file_name(path).to_lower()\n\t\t\t\treturn name == 'v' || name.starts_with('vlang')\n\t\t\t})\n\t}\n\treturn res\n}\n\nfn (s &WinToolchainFlavor) is_applicable() bool {\n\t$if windows {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/project/project.v",
    "content": "module project\n\nimport project.flavors\n\n// get_toolchain_candidates looks for possible places where the V compiler was installed.\n// The function returns an array of candidates, where the first element is the highest priority.\n// If no candidate is found, then an empty array is returned.\n//\n// A priority:\n// 1. `VROOT` or `VEXE` environment variables\n// 2. Symbolic link `/usr/local/bin/v` -> `v` (except Windows)\n// 3. Path from `PATH` environment variable\n// 4. Other additional search options\npub fn get_toolchain_candidates() []string {\n\treturn distinct_strings(flavors.get_toolchain_candidates())\n}\n\nfn distinct_strings(arr []string) []string {\n\tmut set := map[string]bool{}\n\tfor el in arr {\n\t\tset[el] = true\n\t}\n\treturn set.keys()\n}\n"
  },
  {
    "path": "src/server/BackgroundThread.v",
    "content": "module server\n\nimport time\nimport loglib\n\ntype Task = fn ()\n\nenum BackgroundThreadState {\n\tstopped\n\trunning\n}\n\n// BackgroundThread is a simple abstraction a system thread.\n// It accepts tasks and executes them in FIFO order.\n//\n// By executing tasks in a separate thread, we can perform long\n// operations without blocking the main thread.\nstruct BackgroundThread {\n\tend_ch  chan bool\n\ttask_ch chan Task = chan Task{cap: 20}\nmut:\n\tstate BackgroundThreadState\n}\n\n// start starts a background thread.\npub fn (mut b BackgroundThread) start() {\n\tspawn fn [mut b] () {\n\t\tb.state = .running\n\t\tfor {\n\t\t\tselect {\n\t\t\t\ttask := <-b.task_ch {\n\t\t\t\t\ttask()\n\t\t\t\t}\n\t\t\t\t_ := <-b.end_ch {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t100 * time.second {\n\t\t\t\t\t// wait\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// stop stops a background thread.\npub fn (b &BackgroundThread) stop() {\n\tif b.state == .stopped {\n\t\tloglib.warn('Cannot end stopped background thread')\n\t\treturn\n\t}\n\n\tb.end_ch <- true\n}\n\n// queue queues a task to a background thread.\n// Tasks will be executed in FIFO order.\npub fn (b &BackgroundThread) queue(cb fn ()) {\n\tif b.state == .stopped {\n\t\tloglib.warn('Cannot queue task to stopped background thread')\n\t\treturn\n\t}\n\n\tb.task_ch <- cb\n}\n"
  },
  {
    "path": "src/server/README.md",
    "content": "# Description\n\n`server` module describes an implementation of the Language Server Protocol server.\n"
  },
  {
    "path": "src/server/ResponseWriter.v",
    "content": "module server\n\nimport jsonrpc\nimport lsp\n\npub type ResponseWriter = jsonrpc.ResponseWriter\n\nfn (mut wr ResponseWriter) wrap_error(err IError) IError {\n\tif err is none {\n\t\treturn err\n\t}\n\twr.log_message(err.msg(), .error)\n\treturn none\n}\n\n// log_message sends a window/logMessage notification to the client\npub fn (mut wr ResponseWriter) log_message(message string, typ lsp.MessageType) {\n\twr.write_notify('window/logMessage', lsp.LogMessageParams{\n\t\t@type:   typ\n\t\tmessage: message\n\t})\n}\n"
  },
  {
    "path": "src/server/code_lens/CodeLensVisitor.v",
    "content": "module code_lens\n\nimport lsp\nimport config\nimport json\nimport server.tform\nimport analyzer.psi\nimport analyzer.psi.search\n\n@[noinit]\npub struct CodeLensVisitor {\n\tcfg             config.CodeLensConfig\n\turi             lsp.DocumentUri\n\tcontaining_file &psi.PsiFile\n\tis_test_file    bool\nmut:\n\trun_lens_seen   bool\n\tfirst_test_seen bool\n\tresult          []lsp.CodeLens\n}\n\npub fn new_visitor(cfg config.CodeLensConfig, uri lsp.DocumentUri, containing_file &psi.PsiFile) CodeLensVisitor {\n\treturn CodeLensVisitor{\n\t\tcfg:             cfg\n\t\turi:             uri\n\t\tcontaining_file: containing_file\n\t\tis_test_file:    containing_file.is_test_file()\n\t}\n}\n\npub fn (mut v CodeLensVisitor) result() []lsp.CodeLens {\n\treturn v.result\n}\n\npub fn (mut v CodeLensVisitor) accept(root psi.PsiElement) {\n\tmut walker := psi.new_tree_walker(root.node())\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\tv.process_node(node)\n\t}\n}\n\n@[inline]\npub fn (mut v CodeLensVisitor) process_node(node psi.AstNode) {\n\tif node.type_name == .function_declaration && v.cfg.enable_run_lens {\n\t\tv.add_run_lens(node)\n\t}\n\n\tif node.type_name == .function_declaration && v.is_test_file && v.cfg.enable_run_tests_lens {\n\t\tv.add_run_test_lens(node)\n\t}\n\n\tif node.type_name == .interface_declaration && v.cfg.enable_inheritors_lens {\n\t\tv.add_interface_implementations_lens(node)\n\t}\n\n\tif node.type_name == .struct_declaration && v.cfg.enable_super_interfaces_lens {\n\t\tv.add_super_interfaces_lens(node)\n\t}\n}\n\n// add_run_test_lens adds a CodeLens for running the test function or whole file.\npub fn (mut v CodeLensVisitor) add_run_test_lens(node psi.AstNode) {\n\tname_node := node.child_by_field_name('name') or { return }\n\tname := name_node.text(v.containing_file.source_text)\n\n\tif !name.starts_with('test_') {\n\t\treturn\n\t}\n\n\tv.add_lens(node, lsp.Command{\n\t\ttitle:     '▶ Run test'\n\t\tcommand:   'v-analyzer.runTests'\n\t\targuments: [\n\t\t\tv.uri.path(),\n\t\t\tname,\n\t\t]\n\t})\n\n\tif !v.first_test_seen {\n\t\tv.add_lens(node, lsp.Command{\n\t\t\ttitle:     'all file tests'\n\t\t\tcommand:   'v-analyzer.runTests'\n\t\t\targuments: [\n\t\t\t\tv.uri.path(),\n\t\t\t]\n\t\t})\n\t}\n\n\tv.first_test_seen = true\n}\n\n// add_run_lens adds a CodeLens for running the main function.\npub fn (mut v CodeLensVisitor) add_run_lens(node psi.AstNode) {\n\tif v.run_lens_seen {\n\t\t// Since in file there can be only one main function, we don't need to process\n\t\t// other functions if we already found the main function.\n\t\treturn\n\t}\n\n\tname := node.child_by_field_name('name') or { return }\n\tif !name.text_matches(v.containing_file.source_text, 'main') {\n\t\treturn\n\t}\n\n\tv.add_lens(node, lsp.Command{\n\t\ttitle:     '▶ Run workspace'\n\t\tcommand:   'v-analyzer.runWorkspace'\n\t\targuments: [\n\t\t\tv.uri.path(),\n\t\t]\n\t})\n\tv.add_lens(node, lsp.Command{\n\t\ttitle:     'single file'\n\t\tcommand:   'v-analyzer.runFile'\n\t\targuments: [\n\t\t\tv.uri.path(),\n\t\t]\n\t})\n\tv.run_lens_seen = true\n}\n\n// add_interface_implementations_lens adds a CodeLens for showing the implementations of an interface.\n// If the interface has no implementations, no CodeLens is added.\n//\n// By clicking on the CodeLens, the user is shown the implementations.\npub fn (mut v CodeLensVisitor) add_interface_implementations_lens(node psi.AstNode) {\n\telement := psi.create_element(node, v.containing_file)\n\tif element is psi.InterfaceDeclaration {\n\t\timplementations := search.implementations(*element)\n\t\tif implementations.len == 0 {\n\t\t\treturn\n\t\t}\n\n\t\tidentifier_text_range := element.identifier_text_range()\n\t\tlocations := tform.elements_to_locations(implementations)\n\n\t\tlens_title := implementations.len.str() +\n\t\t\tif implementations.len == 1 { ' implementation' } else { ' implementations' }\n\n\t\tv.add_lens(node, lsp.Command{\n\t\t\ttitle:     lens_title\n\t\t\tcommand:   'v-analyzer.showReferences'\n\t\t\targuments: [\n\t\t\t\tv.uri.path(),\n\t\t\t\tjson.encode(lsp.Position{\n\t\t\t\t\tline:      identifier_text_range.line\n\t\t\t\t\tcharacter: identifier_text_range.column\n\t\t\t\t}),\n\t\t\t\tjson.encode(locations),\n\t\t\t]\n\t\t})\n\t}\n}\n\n// add_super_interfaces_lens adds a CodeLens for showing the super interfaces of a struct.\n// If the struct has no super interfaces, no CodeLens is added.\n//\n// By clicking on the CodeLens, the user is shown the super interfaces.\npub fn (mut v CodeLensVisitor) add_super_interfaces_lens(node psi.AstNode) {\n\telement := psi.create_element(node, v.containing_file)\n\tif element is psi.StructDeclaration {\n\t\tsupers := search.supers(*element)\n\t\tif supers.len == 0 {\n\t\t\treturn\n\t\t}\n\n\t\tidentifier_text_range := element.identifier_text_range()\n\t\tlocations := tform.elements_to_locations(supers)\n\n\t\tlens_title := 'implement ' + supers.len.str() +\n\t\t\tif supers.len == 1 { ' interface' } else { ' interfaces' }\n\n\t\tv.add_lens(node, lsp.Command{\n\t\t\ttitle:     lens_title\n\t\t\tcommand:   'v-analyzer.showReferences'\n\t\t\targuments: [\n\t\t\t\tv.uri.path(),\n\t\t\t\tjson.encode(lsp.Position{\n\t\t\t\t\tline:      identifier_text_range.line\n\t\t\t\t\tcharacter: identifier_text_range.column\n\t\t\t\t}),\n\t\t\t\tjson.encode(locations),\n\t\t\t]\n\t\t})\n\t}\n}\n\n// add_lens adds a new CodeLens with the given command.\npub fn (mut v CodeLensVisitor) add_lens(node psi.AstNode, cmd lsp.Command) {\n\tstart_point := node.start_point()\n\tstart := lsp.Position{\n\t\tline:      int(start_point.row)\n\t\tcharacter: int(start_point.column)\n\t}\n\tv.result << lsp.CodeLens{\n\t\trange:   lsp.Range{\n\t\t\tstart: start\n\t\t\tend:   start\n\t\t}\n\t\tcommand: cmd\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/CompletionContext.v",
    "content": "module completion\n\nimport analyzer.psi\nimport lsp\n\npub const dummy_identifier = 'vAnalyzerRulezzz'\n\npub struct CompletionContext {\npub:\n\telement      psi.PsiElement\n\tposition     lsp.Position\n\toffset       u64\n\ttrigger_kind lsp.CompletionTriggerKind\npub mut:\n\tis_test_file        bool\n\tis_start_of_file    bool\n\tis_top_level        bool\n\tis_statement        bool\n\tis_expression       bool\n\tis_type_reference   bool\n\tis_import_name      bool\n\tis_attribute        bool\n\tis_assert_statement bool\n\tinside_loop         bool\n\tafter_dot           bool\n\tafter_at            bool\n\t// if the struct is initialized with keys\n\t// struct Foo { a: int, b: int }\n\tinside_struct_init_with_keys bool\n}\n\npub fn (c CompletionContext) expression() bool {\n\treturn c.is_expression && !c.after_dot && !c.after_at && !c.inside_struct_init_with_keys\n}\n\npub fn (mut c CompletionContext) compute() {\n\tcontaining_file := c.element.containing_file() or { return }\n\tc.is_test_file = containing_file.is_test_file()\n\n\trange := c.element.text_range()\n\tline := range.line\n\tif line < 3 {\n\t\tc.is_start_of_file = true\n\t}\n\tsymbol_at := containing_file.symbol_at(range)\n\tc.after_dot = symbol_at == `.`\n\tc.after_at = c.element.get_text().starts_with('@')\n\n\tparent := c.element.parent() or { return }\n\n\tmatch parent.node().type_name {\n\t\t.import_name { c.is_import_name = true }\n\t\t.keyed_element { c.inside_struct_init_with_keys = true }\n\t\t.type_reference_expression { c.is_type_reference = true }\n\t\t.for_statement, .compile_time_for_statement { c.inside_loop = true }\n\t\telse {}\n\t}\n\n\tif grand := parent.parent() {\n\t\t// Do not consider as reference_expression if it is inside an attribute.\n\t\tif parent.node().type_name == .reference_expression {\n\t\t\tc.is_expression = grand.node().type_name != .key_value_attribute\n\t\t\tif grand.node().type_name == .element_list\n\t\t\t\t|| grand.prev_sibling_of_type(.keyed_element) != none {\n\t\t\t\tc.inside_struct_init_with_keys = true\n\t\t\t}\n\t\t}\n\n\t\tmatch grand.node().type_name {\n\t\t\t.simple_statement { c.is_statement = true }\n\t\t\t.assert_statement { c.is_assert_statement = true }\n\t\t\t.value_attribute { c.is_attribute = true }\n\t\t\t.for_statement, .compile_time_for_statement { c.inside_loop = true }\n\t\t\telse {}\n\t\t}\n\n\t\tif grand_grand := grand.parent() {\n\t\t\tmatch grand_grand.node().type_name {\n\t\t\t\t.source_file { c.is_top_level = true }\n\t\t\t\t.for_statement, .compile_time_for_statement { c.inside_loop = true }\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t}\n\n\tif !c.inside_loop {\n\t\t// long way if the first three parents up are not loops\n\t\tc.inside_loop = c.element.inside(.for_statement)\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/CompletionProvider.v",
    "content": "module completion\n\npub interface CompletionProvider {\n\tis_available(ctx &CompletionContext) bool\nmut:\n\tadd_completion(ctx &CompletionContext, mut result CompletionResultSet)\n}\n"
  },
  {
    "path": "src/server/completion/CompletionResultSet.v",
    "content": "module completion\n\nimport lsp\n\npub struct CompletionResultSet {\nmut:\n\telements []lsp.CompletionItem\n}\n\npub fn (mut c CompletionResultSet) add_element(item lsp.CompletionItem) {\n\tc.elements << item\n}\n\npub fn (mut c CompletionResultSet) elements() []lsp.CompletionItem {\n\treturn c.elements.filter(it.label != '')\n}\n"
  },
  {
    "path": "src/server/completion/providers/AssertCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct AssertCompletionProvider {}\n\nfn (_ &AssertCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\tif !ctx.is_test_file {\n\t\treturn false\n\t}\n\treturn ctx.is_statement || ctx.is_assert_statement\n}\n\nfn (mut _ AssertCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'assert expr'\n\t\tkind:               .keyword\n\t\tinsert_text_format: .snippet\n\t\tinsert_text:        'assert \\${1:expr}'\n\t})\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'assert expr, message'\n\t\tkind:               .keyword\n\t\tinsert_text_format: .snippet\n\t\tinsert_text:        \"assert \\${1:expr}, '\\${2:message}'$0\"\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/AttributesCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\nconst attributes = [\n\t'params',\n\t'noinit',\n\t'required',\n\t'skip',\n\t'assert_continues',\n\t'unsafe',\n\t'manualfree',\n\t'heap',\n\t'nonnull',\n\t'primary',\n\t'inline',\n\t'direct_array_access',\n\t'live',\n\t'flag',\n\t'noinline',\n\t'noreturn',\n\t'typedef',\n\t'console',\n\t'keep_args_alive',\n\t'omitempty',\n\t'json_as_number',\n]\n\nconst attributes_with_colon = [\n\t'sql',\n\t'table',\n\t'deprecated',\n\t'deprecated_after',\n\t'export',\n\t'callconv',\n]\n\npub struct AttributesCompletionProvider {}\n\nfn (k &AttributesCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_attribute\n}\n\nfn (mut k AttributesCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfor attribute in attributes {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:       attribute\n\t\t\tkind:        .struct_\n\t\t\tinsert_text: attribute\n\t\t})\n\t}\n\n\tfor attribute in attributes_with_colon {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:              \"${attribute}: 'value'\"\n\t\t\tkind:               .struct_\n\t\t\tinsert_text:        \"${attribute}: '$1'$0\"\n\t\t\tinsert_text_format: .snippet\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/CompileTimeConstantCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\nconst compile_time_constant = {\n\t'FN':        'The name of the current function'\n\t'METHOD':    'The name of the current method'\n\t'MOD':       'The name of the current module'\n\t'STRUCT':    'The name of the current struct'\n\t'FILE':      'The absolute path:the current file'\n\t'LINE':      'The line number of the current line (as a string)'\n\t'FILE_LINE': 'The relative path and line number of the current line (like @FILE:@LINE)'\n\t'COLUMN':    'The column number of the current line (as a string)'\n\t'VEXE':      'The absolute path:the V compiler executable'\n\t'VEXEROOT':  \"The absolute path:the V compiler executable's root directory\"\n\t'VHASH':     \"The V compiler's git hash\"\n\t'VMOD_FILE': 'The content:the nearest v.mod file'\n\t'VMODROOT':  \"The absolute path:the nearest v.mod file's directory\"\n}\n\npub struct CompileTimeConstantCompletionProvider {}\n\nfn (_ &CompileTimeConstantCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.after_at\n}\n\nfn (mut _ CompileTimeConstantCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfor constant, description in compile_time_constant {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:       '@${constant}'\n\t\t\tkind:        .constant\n\t\t\tdetail:      description\n\t\t\tinsert_text: constant\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/FunctionLikeCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub const function_like_keywords = [\n\t'dump',\n\t'sizeof',\n\t'typeof',\n\t'isreftype',\n\t'__offsetof',\n]\n\npub struct FunctionLikeCompletionProvider {}\n\nfn (k &FunctionLikeCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut k FunctionLikeCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfor keyword in function_like_keywords {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:              '${keyword}()'\n\t\t\tkind:               .keyword\n\t\t\tinsert_text:        '${keyword}($1)$0'\n\t\t\tinsert_text_format: .snippet\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/ImportsCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct ImportsCompletionProvider {}\n\nfn (_ &ImportsCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn (ctx.is_expression || ctx.is_type_reference) && !ctx.after_dot && !ctx.after_at\n\t\t&& !ctx.inside_struct_init_with_keys\n}\n\nfn (mut _ ImportsCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfile := ctx.element.containing_file() or { return }\n\n\timports := file.get_imports()\n\timports_names := imports.map(it.import_name())\n\n\tfor import_name in imports_names {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:       import_name\n\t\t\tkind:        .module_\n\t\t\tinsert_text: import_name\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/InitsCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct InitsCompletionProvider {}\n\nfn (_ &InitsCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut _ InitsCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'chan int{}'\n\t\tkind:               .snippet\n\t\tdetail:             ''\n\t\tinsert_text:        'chan \\${1:int}{}$0'\n\t\tinsert_text_format: .snippet\n\t})\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'map[string]int{}'\n\t\tkind:               .snippet\n\t\tdetail:             ''\n\t\tinsert_text:        'map[\\${1:string}]\\${2:int}{}$0'\n\t\tinsert_text_format: .snippet\n\t})\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'thread int{}'\n\t\tkind:               .snippet\n\t\tdetail:             ''\n\t\tinsert_text:        'thread \\${1:int}{}$0'\n\t\tinsert_text_format: .snippet\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/JsonAttributeCompletionProvider.v",
    "content": "module providers\n\nimport analyzer.psi\nimport server.completion\nimport lsp\nimport utils\nimport v.token\n\npub struct JsonAttributeCompletionProvider {}\n\nfn (p &JsonAttributeCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\tif !ctx.is_attribute {\n\t\treturn false\n\t}\n\treturn ctx.element.inside(.struct_field_declaration)\n}\n\nfn (mut p JsonAttributeCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfield_declaration := ctx.element.parent_of_type(.struct_field_declaration) or { return }\n\tname := if field_declaration is psi.FieldDeclaration {\n\t\tfield_declaration.name()\n\t} else {\n\t\treturn\n\t}\n\n\tjson_name := p.json_name(name)\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              \"json: '${json_name}'\"\n\t\tkind:               .keyword\n\t\tinsert_text:        \"json: '\\${1:${json_name}}'$0\"\n\t\tinsert_text_format: .snippet\n\t})\n}\n\nfn (mut p JsonAttributeCompletionProvider) json_name(field_name string) string {\n\twithout_underscore_and_at := field_name.trim_string_right('_').trim_string_left('@')\n\tname_to_camelize := if token.is_key(without_underscore_and_at) {\n\t\twithout_underscore_and_at\n\t} else {\n\t\tfield_name\n\t}\n\n\treturn utils.snake_case_to_camel_case(name_to_camelize)\n}\n"
  },
  {
    "path": "src/server/completion/providers/KeywordsCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct KeywordsCompletionProvider {}\n\nfn (k &KeywordsCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut k KeywordsCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tk.no_space_keywords([\n\t\t'none',\n\t\t'true',\n\t\t'false',\n\t\t'static',\n\t], mut result)\n}\n\nfn (mut k KeywordsCompletionProvider) no_space_keywords(keywords []string, mut result completion.CompletionResultSet) {\n\tfor keyword in keywords {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:       keyword\n\t\t\tkind:        .keyword\n\t\t\tinsert_text: keyword\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/LoopKeywordsCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct LoopKeywordsCompletionProvider {}\n\nfn (k &LoopKeywordsCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.inside_loop && !ctx.after_dot && !ctx.after_at\n}\n\nfn (mut k LoopKeywordsCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'break'\n\t\tkind:        .keyword\n\t\tinsert_text: 'break'\n\t})\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'continue'\n\t\tkind:        .keyword\n\t\tinsert_text: 'continue'\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/ModuleNameCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\nimport os\n\npub struct ModuleNameCompletionProvider {}\n\nfn (_ &ModuleNameCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\tfile := ctx.element.containing_file() or { return false }\n\tno_module_clause := if _ := file.module_name() {\n\t\tfalse\n\t} else {\n\t\ttrue\n\t}\n\treturn ctx.is_start_of_file && ctx.is_top_level && no_module_clause\n}\n\nfn (mut p ModuleNameCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tfile := ctx.element.containing_file() or { return }\n\tdir := os.dir(file.path)\n\tdir_name := p.transform_module_name(os.file_name(dir))\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'module ${dir_name}'\n\t\tkind:               .keyword\n\t\tinsert_text_format: .snippet\n\t\tinsert_text:        'module ${dir_name}'\n\t})\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'module main'\n\t\tkind:        .keyword\n\t\tinsert_text: 'module main'\n\t})\n}\n\nfn (mut _ ModuleNameCompletionProvider) transform_module_name(raw_name string) string {\n\treturn raw_name\n\t\t.replace('-', '_')\n\t\t.replace(' ', '_')\n\t\t.to_lower()\n}\n"
  },
  {
    "path": "src/server/completion/providers/ModulesImportProvider.v",
    "content": "module providers\n\nimport analyzer.psi\nimport server.completion\nimport lsp\n\npub struct ModulesImportProvider {}\n\nfn (m &ModulesImportProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_import_name\n}\n\nfn (mut m ModulesImportProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\telement := ctx.element\n\tparent_path := element.parent_nth(2) or { return }\n\tbefore_path := parent_path.get_text().trim_string_right(completion.dummy_identifier)\n\n\tmodules := psi.get_all_modules()\n\n\tfor module_ in modules {\n\t\tif module_ == 'main' {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !module_.starts_with(before_path) {\n\t\t\tcontinue\n\t\t}\n\t\tname_without_prefix := module_.trim_string_left(before_path)\n\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:              name_without_prefix\n\t\t\tkind:               .module_\n\t\t\tdetail:             ''\n\t\t\tdocumentation:      ''\n\t\t\tinsert_text:        name_without_prefix\n\t\t\tinsert_text_format: .plain_text\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/NilKeywordCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct NilKeywordCompletionProvider {}\n\nfn (k &NilKeywordCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut k NilKeywordCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tinside_unsafe := ctx.element.inside(.unsafe_expression)\n\n\tinsert_text := if !inside_unsafe {\n\t\t'unsafe { nil }'\n\t} else {\n\t\t'nil'\n\t}\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'nil'\n\t\tkind:        .keyword\n\t\tinsert_text: insert_text\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/OrBlockExpressionCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct OrBlockExpressionCompletionProvider {}\n\nfn (k &OrBlockExpressionCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut k OrBlockExpressionCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'or { ... }'\n\t\tkind:               .keyword\n\t\tinsert_text:        'or { $0 }'\n\t\tinsert_text_format: .snippet\n\t})\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'or { panic(err) }'\n\t\tkind:        .keyword\n\t\tinsert_text: 'or { panic(err) }'\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/PureBlockExpressionCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct PureBlockExpressionCompletionProvider {}\n\nfn (k &PureBlockExpressionCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.expression()\n}\n\nfn (mut k PureBlockExpressionCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tone_line := if parent := ctx.element.parent_nth(2) {\n\t\tif parent.node().type_name == .simple_statement {\n\t\t\tfalse\n\t\t} else {\n\t\t\ttrue\n\t\t}\n\t} else {\n\t\ttrue\n\t}\n\n\tinsert_text := if one_line {\n\t\t'unsafe { $0 }'\n\t} else {\n\t\t'unsafe {\\n\\t$0\\n}'\n\t}\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'unsafe { ... }'\n\t\tkind:               .keyword\n\t\tinsert_text:        insert_text\n\t\tinsert_text_format: .snippet\n\t\tinsert_text_mode:   .adjust_indentation\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/PureBlockStatementCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\npub struct PureBlockStatementCompletionProvider {}\n\nfn (k &PureBlockStatementCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_statement && !ctx.after_dot && !ctx.after_at\n}\n\nfn (mut k PureBlockStatementCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:              'defer { ... }'\n\t\tkind:               .keyword\n\t\tinsert_text:        'defer {\\n\\t$0\\n}'\n\t\tinsert_text_format: .snippet\n\t\tinsert_text_mode:   .adjust_indentation\n\t})\n}\n"
  },
  {
    "path": "src/server/completion/providers/ReferenceCompletionProcessor.v",
    "content": "module providers\n\nimport lsp\nimport strings\nimport analyzer.psi\nimport analyzer.lang\nimport server.completion\n\npub struct ReferenceCompletionProcessor {\npub:\n\tfile       &psi.PsiFile\n\tmodule_fqn string\n\troot       string\n\tctx        &completion.CompletionContext\nmut:\n\tresult map[string]lsp.CompletionItem\n}\n\npub fn (mut c ReferenceCompletionProcessor) elements() []lsp.CompletionItem {\n\treturn c.result.values()\n}\n\nfn (mut c ReferenceCompletionProcessor) is_local_resolve(element psi.PsiElement) bool {\n\tfile := element.containing_file() or { return false }\n\telement_module_fqn := file.module_fqn()\n\tequal := c.module_fqn == element_module_fqn\n\tif equal && c.module_fqn == 'main' {\n\t\t// We check that the module matches, but if it is main, then we need to check\n\t\t// that the file is in the workspace.\n\t\treturn file.path.starts_with(c.root)\n\t}\n\treturn equal\n}\n\nfn (mut c ReferenceCompletionProcessor) execute(element psi.PsiElement) bool {\n\tis_public, name := if element is psi.PsiNamedElement {\n\t\telement.is_public(), element.name()\n\t} else {\n\t\ttrue, ''\n\t}\n\tlocal_resolve := c.is_local_resolve(element)\n\n\tif !is_public && !local_resolve {\n\t\treturn true\n\t}\n\n\tif element is psi.VarDefinition {\n\t\tc.add_item(\n\t\t\tlabel:              name\n\t\t\tkind:               .variable\n\t\t\tdetail:             element.get_type().readable_name()\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdescription: element.get_type().readable_name()\n\t\t\t}\n\t\t\tdocumentation:      ''\n\t\t\tinsert_text:        name\n\t\t\tinsert_text_format: .plain_text\n\t\t\tsort_text:          '0${name}' // variables should go first\n\t\t)\n\t}\n\n\tif element is psi.ParameterDeclaration {\n\t\tc.add_item(\n\t\t\tlabel:              name\n\t\t\tkind:               .variable\n\t\t\tdetail:             element.get_type().readable_name()\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdescription: element.get_type().readable_name()\n\t\t\t}\n\t\t\tdocumentation:      ''\n\t\t\tinsert_text:        name\n\t\t\tinsert_text_format: .plain_text\n\t\t\tsort_text:          '0${name}' // parameters should go first\n\t\t)\n\t}\n\n\tif element is psi.Receiver {\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .variable\n\t\t\tdetail:             element.get_type().readable_name()\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdescription: element.get_type().readable_name()\n\t\t\t}\n\t\t\tdocumentation:      ''\n\t\t\tinsert_text:        element.name()\n\t\t\tinsert_text_format: .plain_text\n\t\t)\n\t}\n\n\tif element is psi.FunctionOrMethodDeclaration {\n\t\treceiver_text := if receiver := element.receiver() {\n\t\t\treceiver.get_text() + ' '\n\t\t} else {\n\t\t\t''\n\t\t}\n\n\t\tmut insert_name := element.name()\n\t\tif name.starts_with('$') {\n\t\t\tinsert_name = insert_name[1..]\n\t\t}\n\n\t\tsignature := element.signature() or { return true }\n\t\thas_params := signature.parameters().len > 0\n\n\t\tgeneric_parameters_text := if generic_parameters := element.generic_parameters() {\n\t\t\tgeneric_parameters.text_presentation()\n\t\t} else {\n\t\t\t''\n\t\t}\n\n\t\ttext_ranga := c.ctx.element.text_range()\n\t\tparen_after_cursor := if ctx_file := c.ctx.element.containing_file() {\n\t\t\tsym := ctx_file.symbol_at(psi.TextRange{\n\t\t\t\tline:   text_ranga.line\n\t\t\t\tcolumn: text_ranga.end_column + 1\n\t\t\t})\n\t\t\tsym == `(`\n\t\t} else {\n\t\t\tfalse\n\t\t}\n\n\t\tmut insert_text_builder := strings.new_builder(20)\n\t\tinsert_text_builder.write_string(insert_name)\n\n\t\t// we don't want add extra parentheses if the cursor is before the parentheses\n\t\t// It happens when user replaces the function name in the call, for example:\n\t\t// 1. foo()\n\t\t// 2. remove foo, type bar and autocomplete\n\t\t// 3. bar()\n\t\t// without this check we would get bar()()\n\t\tif !paren_after_cursor {\n\t\t\tif has_params {\n\t\t\t\tinsert_text_builder.write_string('($1)')\n\t\t\t} else {\n\t\t\t\tinsert_text_builder.write_string('()')\n\t\t\t}\n\t\t}\n\t\tinsert_text_builder.write_string('$0')\n\n\t\tc.add_item(\n\t\t\tlabel:              '${name}'\n\t\t\tkind:               if receiver_text == '' { .function } else { .method }\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdetail: signature.get_text()\n\t\t\t}\n\t\t\tdetail:             'fn ${receiver_text}${element.name()}${generic_parameters_text}${signature.get_text()}'\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        insert_text_builder.str()\n\t\t\tinsert_text_format: .snippet\n\t\t\tsort_text:          '1${name}' // functions should go second\n\t\t)\n\t}\n\n\tif element is psi.StaticMethodDeclaration {\n\t\treceiver_text := if receiver := element.receiver() {\n\t\t\treceiver.get_text() + ' '\n\t\t} else {\n\t\t\t''\n\t\t}\n\n\t\tmut insert_name := element.name()\n\t\tif name.starts_with('$') {\n\t\t\tinsert_name = insert_name[1..]\n\t\t}\n\n\t\tsignature := element.signature() or { return true }\n\t\thas_params := signature.parameters().len > 0\n\n\t\tgeneric_parameters_text := if generic_parameters := element.generic_parameters() {\n\t\t\tgeneric_parameters.text_presentation()\n\t\t} else {\n\t\t\t''\n\t\t}\n\n\t\ttext_ranga := c.ctx.element.text_range()\n\t\tparen_after_cursor := if ctx_file := c.ctx.element.containing_file() {\n\t\t\tsym := ctx_file.symbol_at(psi.TextRange{\n\t\t\t\tline:   text_ranga.line\n\t\t\t\tcolumn: text_ranga.end_column + 1\n\t\t\t})\n\t\t\tsym == `{`\n\t\t} else {\n\t\t\tfalse\n\t\t}\n\n\t\tmut insert_text_builder := strings.new_builder(20)\n\t\tinsert_text_builder.write_string(insert_name)\n\n\t\t// we don't want add extra parentheses if the cursor is before the parentheses\n\t\t// It happens when user replaces the function name in the call, for example:\n\t\t// 1. foo()\n\t\t// 2. remove foo, type bar and autocomplete\n\t\t// 3. bar()\n\t\t// without this check we would get bar()()\n\t\tif !paren_after_cursor {\n\t\t\tif has_params {\n\t\t\t\tinsert_text_builder.write_string('($1)')\n\t\t\t} else {\n\t\t\t\tinsert_text_builder.write_string('()')\n\t\t\t}\n\t\t}\n\t\tinsert_text_builder.write_string('$0')\n\n\t\tc.add_item(\n\t\t\tlabel:              '${name}'\n\t\t\tkind:               .method\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdetail: signature.get_text()\n\t\t\t}\n\t\t\tdetail:             'fn ${receiver_text}${element.name()}${generic_parameters_text}${signature.get_text()}'\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        insert_text_builder.str()\n\t\t\tinsert_text_format: .snippet\n\t\t\tsort_text:          '1${name}' // functions should go second\n\t\t)\n\t}\n\n\tif element is psi.StructDeclaration {\n\t\tif name == 'map' || name == 'array' {\n\t\t\t// it makes no sense to create these structures directly\n\t\t\treturn true\n\t\t}\n\n\t\ttext_ranga := c.ctx.element.text_range()\n\t\tparen_after_cursor := if ctx_file := c.ctx.element.containing_file() {\n\t\t\tsym := ctx_file.symbol_at(psi.TextRange{\n\t\t\t\tline:   text_ranga.line\n\t\t\t\tcolumn: text_ranga.end_column + 1\n\t\t\t})\n\t\t\tsym == `{`\n\t\t} else {\n\t\t\tfalse\n\t\t}\n\n\t\tinsert_text := if c.ctx.is_type_reference || paren_after_cursor {\n\t\t\tname // if it is a reference to a type, then insert only the name\n\t\t} else {\n\t\t\tname + '{$1}$0'\n\t\t}\n\n\t\tc.add_item(\n\t\t\tlabel:              name\n\t\t\tkind:               .struct_\n\t\t\tdetail:             ''\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        insert_text\n\t\t\tinsert_text_format: .snippet\n\t\t)\n\t}\n\n\tif element is psi.ConstantDefinition {\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .constant\n\t\t\tdetail:             element.get_type().readable_name()\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdescription: element.get_type().readable_name()\n\t\t\t}\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        element.name()\n\t\t\tinsert_text_format: .plain_text\n\t\t)\n\t}\n\n\tif element is psi.FieldDeclaration {\n\t\tzero_value := lang.get_zero_value_for(element.get_type()).replace('}', '\\\\}')\n\n\t\tinsert_text := if c.ctx.inside_struct_init_with_keys {\n\t\t\telement.name() + ': \\${1:${zero_value}}'\n\t\t} else {\n\t\t\telement.name()\n\t\t}\n\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .field\n\t\t\tdetail:             element.get_type().readable_name()\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdescription: element.get_type().readable_name()\n\t\t\t}\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        insert_text\n\t\t\tinsert_text_format: .snippet\n\t\t)\n\t}\n\n\tif element is psi.InterfaceMethodDeclaration {\n\t\tsignature := element.signature() or { return true }\n\t\thas_params := signature.parameters().len > 0\n\n\t\tmut insert_text_builder := strings.new_builder(20)\n\t\tinsert_text_builder.write_string(element.name())\n\t\tif has_params {\n\t\t\tinsert_text_builder.write_string('($1)')\n\t\t} else {\n\t\t\tinsert_text_builder.write_string('()')\n\t\t}\n\n\t\towner_name := if owner := element.owner() {\n\t\t\t' of ${owner.name()}'\n\t\t} else {\n\t\t\t''\n\t\t}\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .method\n\t\t\tdetail:             'fn ${element.name()}${signature.get_text()}'\n\t\t\tlabel_details:      lsp.CompletionItemLabelDetails{\n\t\t\t\tdetail:      signature.get_text()\n\t\t\t\tdescription: owner_name\n\t\t\t}\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        insert_text_builder.str()\n\t\t\tinsert_text_format: .snippet\n\t\t)\n\t}\n\n\tif element is psi.EnumDeclaration {\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .enum_\n\t\t\tdetail:             ''\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        element.name()\n\t\t\tinsert_text_format: .plain_text\n\t\t)\n\t}\n\n\tif element is psi.EnumFieldDeclaration {\n\t\tc.add_item(\n\t\t\tlabel:              element.name()\n\t\t\tkind:               .enum_member\n\t\t\tdetail:             ''\n\t\t\tdocumentation:      element.doc_comment()\n\t\t\tinsert_text:        element.name()\n\t\t\tinsert_text_format: .plain_text\n\t\t)\n\t}\n\n\tif element is psi.GenericParameter {\n\t\tc.add_item(\n\t\t\tlabel: element.name()\n\t\t\tkind:  .type_parameter\n\t\t)\n\t}\n\n\tif element is psi.GlobalVarDefinition {\n\t\tfile := element.containing_file()\n\t\tmodule_name := if file != none { file.module_fqn() } else { '' }\n\t\tc.add_item(\n\t\t\tlabel:         element.name()\n\t\t\tlabel_details: lsp.CompletionItemLabelDetails{\n\t\t\t\tdetail: ' (global defined in ${module_name})'\n\t\t\t}\n\t\t\tkind:          .variable\n\t\t\tinsert_text:   element.name()\n\t\t)\n\t}\n\n\treturn true\n}\n\nfn (mut c ReferenceCompletionProcessor) add_item(item lsp.CompletionItem) {\n\tif item.label in c.result {\n\t\treturn\n\t}\n\n\tc.result[item.label] = item\n}\n"
  },
  {
    "path": "src/server/completion/providers/ReferenceCompletionProvider.v",
    "content": "module providers\n\nimport analyzer.psi\nimport analyzer.lang\nimport server.completion\nimport analyzer.psi.types\n\npub struct ReferenceCompletionProvider {\npub mut:\n\tprocessor &ReferenceCompletionProcessor\n}\n\nfn (_ &ReferenceCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_expression || ctx.is_type_reference\n}\n\nfn (mut r ReferenceCompletionProvider) add_completion(ctx &completion.CompletionContext, mut _ completion.CompletionResultSet) {\n\telement := ctx.element\n\ttext := element.get_text()\n\tif text.starts_with('@') {\n\t\t// See `CompileTimeConstantCompletionProvider`\n\t\treturn\n\t}\n\n\tparent := element.parent() or { return }\n\tcontaining_file := parent.containing_file()\n\n\tif parent is psi.ReferenceExpressionBase {\n\t\tsub := psi.SubResolver{\n\t\t\tcontaining_file: containing_file\n\t\t\telement:         parent\n\t\t\tfor_types:       parent is psi.TypeReferenceExpression\n\t\t}\n\n\t\tvariants := StructLiteralCompletion{}.allowed_variants(ctx, parent)\n\t\tfield_initializers := StructLiteralCompletion{}.get_field_initializers(element)\n\t\talready_assigned := StructLiteralCompletion{}.already_assigned_fields(field_initializers)\n\n\t\tif variants != .none_ {\n\t\t\tr.process_fields(ctx, parent as psi.PsiElement, already_assigned)\n\t\t}\n\n\t\tif variants != .field_name_only {\n\t\t\tsub.process_resolve_variants(mut r.processor)\n\t\t}\n\t}\n}\n\nfn (mut r ReferenceCompletionProvider) process_fields(ctx &completion.CompletionContext, element psi.PsiElement,\n\talready_assigned []string) {\n\tgrand := element.parent() or { return }\n\tif grand.node().type_name != .element_list {\n\t\treturn\n\t}\n\n\ttype_initializer := grand.parent_nth(2) or { return }\n\n\tif type_initializer is psi.TypeInitializer {\n\t\ttyp := type_initializer.get_type()\n\n\t\tqualified_name := if typ is types.ArrayType {\n\t\t\t'stubs.ArrayInit'\n\t\t} else if typ is types.ChannelType {\n\t\t\t'stubs.ChanInit'\n\t\t} else {\n\t\t\ttyp.qualified_name()\n\t\t}\n\n\t\tif interface_ := psi.find_interface(qualified_name) {\n\t\t\tfor field in interface_.fields() {\n\t\t\t\tif field is psi.FieldDeclaration {\n\t\t\t\t\tif !field.is_public() && !lang.is_same_module(ctx.element, *field) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif field.name() in already_assigned {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tr.processor.execute(field)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif struct_ := psi.find_struct(qualified_name) {\n\t\t\tfor field in struct_.fields() {\n\t\t\t\tif field is psi.FieldDeclaration {\n\t\t\t\t\tif !field.is_public() && !lang.is_same_module(ctx.element, *field) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif field.name() in already_assigned {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tr.processor.execute(field)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/ReturnCompletionProvider.v",
    "content": "module providers\n\nimport analyzer.psi\nimport server.completion\nimport analyzer.psi.types\nimport analyzer.lang\nimport lsp\n\npub struct ReturnCompletionProvider {}\n\nfn (_ &ReturnCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_statement && !ctx.after_at\n}\n\nfn (mut _ ReturnCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\telement := ctx.element\n\n\tparent_function := element.parent_of_any_type(.function_declaration, .function_literal) or {\n\t\treturn\n\t}\n\tsignature := if parent_function is psi.SignatureOwner {\n\t\tparent_function.signature() or { return }\n\t} else {\n\t\treturn\n\t}\n\n\tfunction_type := signature.get_type()\n\tif function_type is types.FunctionType {\n\t\thas_result_type := !function_type.no_result\n\t\tresult_type := function_type.result\n\t\tif result_type is types.PrimitiveType {\n\t\t\tif result_type.name == 'bool' {\n\t\t\t\tresult.add_element(lsp.CompletionItem{\n\t\t\t\t\tlabel: 'return true'\n\t\t\t\t\tkind:  .text\n\t\t\t\t})\n\t\t\t\tresult.add_element(lsp.CompletionItem{\n\t\t\t\t\tlabel: 'return false'\n\t\t\t\t\tkind:  .text\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif has_result_type {\n\t\t\tzero_value := lang.get_zero_value_for(result_type)\n\t\t\tresult.add_element(lsp.CompletionItem{\n\t\t\t\tlabel: 'return ${zero_value}'\n\t\t\t\tkind:  .text\n\t\t\t})\n\t\t}\n\n\t\tlabel := if !has_result_type {\n\t\t\t'return'\n\t\t} else {\n\t\t\t'return '\n\t\t}\n\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel: label\n\t\t\tkind:  .text\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/server/completion/providers/StructLiteralCompletion.v",
    "content": "module providers\n\nimport analyzer.psi\nimport server.completion\nimport analyzer.psi.types\n\n// Describes struct literal completion variants that should be suggested.\npub enum Variants {\n\t// Only struct field names should be suggested.\n\t// Indicates that field:value initializers are used in this struct literal.\n\t// For example, `Struct{field1: \"\", caret}`.\n\tfield_name_only\n\t// Only values should be suggested.\n\t// Indicates that value initializers are used in this struct literal.\n\t// For example, `Struct{\"\", caret}`.\n\tvalue_only\n\t// Both struct field names and values should be suggested.\n\t// Indicates that there's no reliable way to determine whether field:value or value initializers are used.\n\t// Example 1: `Struct{caret}`.\n\t// Example 2: `Struct{field1:\"\", \"\", caret}`\n\tboth\n\t// Indicates that struct literal completion should not be available.\n\tnone_\n}\n\npub struct StructLiteralCompletion {}\n\npub fn (s &StructLiteralCompletion) allowed_variants(ctx &completion.CompletionContext, ref psi.ReferenceExpressionBase) Variants {\n\tif ctx.after_dot {\n\t\treturn .none_\n\t}\n\n\telement := ref as psi.PsiElement\n\n\tmut parent := element.parent() or { return .none_ }\n\tfor parent is psi.UnaryExpression {\n\t\tparent = parent.parent() or { return .none_ }\n\t}\n\n\tif parent.node().type_name != .element_list {\n\t\treturn .none_\n\t}\n\n\tif type_initializer := parent.parent_nth(2) {\n\t\tif type_initializer is psi.TypeInitializer {\n\t\t\ttyp := type_initializer.get_type()\n\t\t\tif typ is types.ArrayType {\n\t\t\t\t// for []int{<caret>}, allow only fields\n\t\t\t\treturn .field_name_only\n\t\t\t}\n\t\t\tif typ is types.ChannelType {\n\t\t\t\t// for chan int{<caret>}, allow only fields\n\t\t\t\treturn .field_name_only\n\t\t\t}\n\t\t}\n\t}\n\n\tfield_initializers := s.get_field_initializers(element)\n\n\tmut has_value_initializers := false\n\tmut has_field_value_initializers := false\n\n\tfor initializer in field_initializers {\n\t\tif initializer.is_equal(element) {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey_value := initializer.node().type_name == .keyed_element\n\t\thas_field_value_initializers = has_field_value_initializers || key_value\n\t\thas_value_initializers = has_value_initializers || !key_value\n\t}\n\n\treturn if has_field_value_initializers && !has_value_initializers {\n\t\t.field_name_only\n\t} else if !has_field_value_initializers && has_value_initializers {\n\t\t.value_only\n\t} else {\n\t\t.both\n\t}\n}\n\npub fn (s &StructLiteralCompletion) already_assigned_fields(elements []psi.PsiElement) []string {\n\tmut res := []string{cap: elements.len}\n\n\tfor element in elements {\n\t\tif element.node().type_name == .keyed_element {\n\t\t\tif key := element.first_child() {\n\t\t\t\tres << key.get_text()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn res\n}\n\npub fn (s &StructLiteralCompletion) get_field_initializers(element psi.PsiElement) []psi.PsiElement {\n\tif type_initializer := element.parent_of_type(.type_initializer) {\n\t\tif type_initializer is psi.TypeInitializer {\n\t\t\treturn type_initializer.element_list()\n\t\t}\n\t}\n\n\treturn []\n}\n"
  },
  {
    "path": "src/server/completion/providers/TopLevelCompletionProvider.v",
    "content": "module providers\n\nimport server.completion\nimport lsp\n\nstruct TopLevelVariant {\n\tsearch_text string\n\tinsert_text string\n}\n\npub const top_level_map = {\n\t'fn name() { ... }':       TopLevelVariant{'fn', 'fn \\${1:name}($2) {\\n\\t$0\\n}'}\n\t'struct Name { ... }':     TopLevelVariant{'struct', 'struct \\${1:Name} {\\n\\t$0\\n}'}\n\t'interface IName { ... }': TopLevelVariant{'interface', 'interface \\${1:IName} {\\n\\t$0\\n}'}\n\t'enum Colors { ... }':     TopLevelVariant{'enum', 'enum \\${1:Colors} {\\n\\t$0\\n}'}\n\t'type MyString = string':  TopLevelVariant{'type', 'type \\${1:MyString} = \\${2:string}$0'}\n\t'const secret = 100':      TopLevelVariant{'const', 'const \\${1:secret} = \\${2:100}$0'}\n}\n\npub struct TopLevelCompletionProvider {}\n\nfn (k &TopLevelCompletionProvider) is_available(ctx &completion.CompletionContext) bool {\n\treturn ctx.is_top_level\n}\n\nfn (mut k TopLevelCompletionProvider) add_completion(ctx &completion.CompletionContext, mut result completion.CompletionResultSet) {\n\tk.pub_keyword(mut result)\n}\n\nfn (mut k TopLevelCompletionProvider) pub_keyword(mut result completion.CompletionResultSet) {\n\tfor label, variant in top_level_map {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:              label\n\t\t\tkind:               .keyword\n\t\t\tfilter_text:        variant.search_text\n\t\t\tinsert_text:        variant.insert_text\n\t\t\tinsert_text_format: .snippet\n\t\t})\n\t}\n\n\tfor label, variant in top_level_map {\n\t\tresult.add_element(lsp.CompletionItem{\n\t\t\tlabel:              'pub ${label}'\n\t\t\tkind:               .keyword\n\t\t\tfilter_text:        'pub ${variant.search_text}'\n\t\t\tinsert_text:        'pub ${variant.insert_text}'\n\t\t\tinsert_text_format: .snippet\n\t\t})\n\t}\n\n\tresult.add_element(lsp.CompletionItem{\n\t\tlabel:       'import'\n\t\tkind:        .keyword\n\t\tinsert_text: 'import '\n\t})\n}\n"
  },
  {
    "path": "src/server/diagnostics.v",
    "content": "module server\n\nimport lsp\nimport time\nimport loglib\nimport server.tform\nimport server.inspections\nimport server.inspections.compiler\n\npub fn (mut ls LanguageServer) run_diagnostics_in_bg(uri lsp.DocumentUri) {\n\tls.bg.queue(fn [mut ls, uri] () {\n\t\tls.run_diagnostics(uri)\n\t})\n}\n\npub fn (mut ls LanguageServer) run_diagnostics(uri lsp.DocumentUri) {\n\twatch := time.new_stopwatch(auto_start: true)\n\tproject_root := ls.project_resolver.resolve(uri)\n\tls.reporter.clear(uri)\n\tls.reporter.run_all_inspections(uri, project_root)\n\tls.reporter.publish(mut ls.writer, uri)\n\n\tloglib.with_fields({\n\t\t'caller':   @METHOD\n\t\t'duration': watch.elapsed().str()\n\t}).info('Updated diagnostics')\n}\n\npub struct DiagnosticReporter {\nmut:\n\tcompiler_path string\n\treports       map[lsp.DocumentUri][]inspections.Report\n}\n\nfn (mut d DiagnosticReporter) run_all_inspections(uri lsp.DocumentUri, project_root string) {\n\tmut source := compiler.CompilerReportsSource{\n\t\tcompiler_path: d.compiler_path\n\t}\n\td.reports[uri] = source.process(uri, project_root)\n}\n\nfn (mut d DiagnosticReporter) clear(uri lsp.DocumentUri) {\n\td.reports[uri] = []\n}\n\nfn (mut d DiagnosticReporter) publish(mut wr ResponseWriter, uri lsp.DocumentUri) {\n\treports := d.reports[uri] or { return }\n\twr.publish_diagnostics(lsp.PublishDiagnosticsParams{\n\t\turi:         uri\n\t\tdiagnostics: reports.map(d.convert_report(it))\n\t})\n}\n\nfn (_ &DiagnosticReporter) convert_report(report inspections.Report) lsp.Diagnostic {\n\tpossibly_unused := report.message.starts_with('unused')\n\tpossibly_deprecated := report.message.contains('deprecated')\n\tmut tags := []lsp.DiagnosticTag{}\n\tif possibly_unused {\n\t\ttags << lsp.DiagnosticTag.unnecessary\n\t}\n\tif possibly_deprecated {\n\t\ttags << lsp.DiagnosticTag.deprecated\n\t}\n\n\treturn lsp.Diagnostic{\n\t\trange:    tform.text_range_to_lsp_range(report.range)\n\t\tseverity: match report.kind {\n\t\t\t.error { lsp.DiagnosticSeverity.error }\n\t\t\t.warning { lsp.DiagnosticSeverity.warning }\n\t\t\t.notice { lsp.DiagnosticSeverity.information }\n\t\t}\n\t\tsource:   'compiler'\n\t\tmessage:  report.message\n\t\ttags:     tags\n\t}\n}\n\n// publish_diagnostics sends errors, warnings and other diagnostics to the editor\nfn (mut wr ResponseWriter) publish_diagnostics(params lsp.PublishDiagnosticsParams) {\n\twr.write_notify('textDocument/publishDiagnostics', params)\n}\n"
  },
  {
    "path": "src/server/documentation/keywords_provider.v",
    "content": "module documentation\n\nimport strings\nimport analyzer.psi\nimport analyzer.psi.types\n\n// KeywordProvider unlike `Provider` creates documentation not for named elements i\n// but for language keywords.\n// This documentation is used to educate users of the language and as an entry point\n// to the language documentation.\npub struct KeywordProvider {\nmut:\n\tsb strings.Builder = strings.new_builder(100)\n}\n\npub fn (mut p KeywordProvider) documentation(element psi.PsiElement) ?string {\n\ttext := element.get_text()\n\n\tif text == 'chan' {\n\t\tp.chan_documentation()\n\t\treturn p.sb.str()\n\t}\n\n\treturn none\n}\n\nfn (mut p KeywordProvider) chan_documentation() ? {\n\tstruct_ := psi.find_struct(types.chan_init_type.qualified_name())?\n\tdoc := struct_.doc_comment()\n\tp.sb.write_string(doc)\n}\n"
  },
  {
    "path": "src/server/documentation/provider.v",
    "content": "module documentation\n\nimport analyzer.psi\nimport strings\nimport os\nimport loglib\n\npub struct Provider {\nmut:\n\tsb strings.Builder = strings.new_builder(100)\n}\n\npub fn (mut p Provider) documentation(element psi.PsiElement) ?string {\n\tif element is psi.ModuleClause {\n\t\tp.module_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.FunctionOrMethodDeclaration {\n\t\tp.function_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.StaticMethodDeclaration {\n\t\tp.static_method_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.StructDeclaration {\n\t\tp.struct_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.InterfaceDeclaration {\n\t\tp.interface_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.InterfaceMethodDeclaration {\n\t\tp.interface_method_declaration_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.EnumDeclaration {\n\t\tp.enum_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.ConstantDefinition {\n\t\tp.const_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.VarDefinition {\n\t\tp.variable_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.GlobalVarDefinition {\n\t\tp.global_variable_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.ParameterDeclaration {\n\t\tp.parameter_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.Receiver {\n\t\tp.receiver_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.FieldDeclaration {\n\t\tp.field_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.EmbeddedDefinition {\n\t\tp.embedded_definition_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.EnumFieldDeclaration {\n\t\tp.enum_field_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.TypeAliasDeclaration {\n\t\tp.type_alias_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.ImportSpec {\n\t\tp.import_spec_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\tif element is psi.GenericParameter {\n\t\tp.generic_parameter_documentation(element)?\n\t\treturn p.sb.str()\n\t}\n\n\treturn none\n}\n\nfn (mut p Provider) import_spec_documentation(element psi.ImportSpec) ? {\n\tmodule_fqn := element.qualified_name()\n\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('module ${module_fqn}')\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\n\tdir := element.resolve_directory()\n\tmut readme_path := os.join_path(dir, 'README.md')\n\tif !os.exists(readme_path) && os.file_name(dir) == 'src' {\n\t\treadme_path = os.join_path(os.dir(dir), 'README.md')\n\t}\n\tif os.exists(readme_path) {\n\t\tp.write_separator()\n\t\tmut content := os.read_file(readme_path) or { return }\n\t\tmut lines := content.split_into_lines()\n\t\tif lines.len > 0 && lines.first().contains('Description') {\n\t\t\tlines = lines[1..].clone()\n\t\t\tcontent = lines.join('\\n')\n\t\t}\n\t\tcontent = content.replace('# ', '### ')\n\t\tp.sb.write_string(content)\n\t}\n\n\tp.write_separator()\n\n\tp.sb.write_string('---\\n')\n\tp.sb.write_string('```${dir}```\\n')\n}\n\nfn (mut p Provider) module_documentation(element psi.ModuleClause) ? {\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('module ')\n\tp.sb.write_string(element.name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) function_documentation(element psi.FunctionOrMethodDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tsignature := element.signature()?\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('fn ')\n\tif receiver := element.receiver() {\n\t\tp.sb.write_string(receiver.get_text())\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string(element.name())\n\tp.write_generic_parameters(element)\n\tp.write_signature(signature)\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) static_method_documentation(element psi.StaticMethodDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tsignature := element.signature()?\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('fn ')\n\tif receiver := element.receiver() {\n\t\tp.sb.write_string(receiver.get_text())\n\t\tp.sb.write_string('.')\n\t}\n\tp.sb.write_string(element.name())\n\tp.write_generic_parameters(element)\n\tp.write_signature(signature)\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) struct_documentation(element psi.StructDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('struct ')\n\tp.sb.write_string(element.name())\n\tp.write_generic_parameters(element)\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) interface_documentation(element psi.InterfaceDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('interface ')\n\tp.sb.write_string(element.name())\n\tp.write_generic_parameters(element)\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) interface_method_declaration_documentation(element psi.InterfaceMethodDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tsignature := element.signature()?\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('pub fn ')\n\n\tif owner := element.owner() {\n\t\tp.sb.write_string(owner.name())\n\t\tp.sb.write_string('.')\n\t}\n\n\tp.sb.write_string(element.name())\n\tp.write_signature(signature)\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) enum_documentation(element psi.EnumDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('enum ')\n\tp.sb.write_string(element.name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) const_documentation(element psi.ConstantDefinition) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('const ')\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string(' = ')\n\tif value := element.expression() {\n\t\tp.sb.write_string(value.get_text())\n\t\tif element.stub_based() {\n\t\t\tif mut file := value.containing_file() {\n\t\t\t\tfile.free()\n\t\t\t}\n\t\t}\n\t}\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) variable_documentation(element psi.VarDefinition) ? {\n\tp.sb.write_string('Local **variable**\\n')\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.mutability_modifiers() {\n\t\tp.write_mutability_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) global_variable_documentation(element psi.GlobalVarDefinition) ? {\n\tp.sb.write_string('Global **variable**\\n')\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('__global ')\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) parameter_documentation(element psi.ParameterDeclaration) ? {\n\tp.sb.write_string('Function **parameter**\\n')\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.mutability_modifiers() {\n\t\tp.write_mutability_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) field_documentation(element psi.FieldDeclaration) ? {\n\tp.sb.write_string('```v\\n')\n\n\tis_mut, is_pub := element.is_mutable_public()\n\n\tif is_pub {\n\t\tp.sb.write_string('pub ')\n\t}\n\tif is_mut {\n\t\tp.sb.write_string('mut ')\n\t}\n\n\tif owner := element.owner() {\n\t\tif owner is psi.PsiNamedElement {\n\t\t\tp.sb.write_string(owner.name())\n\t\t\tp.sb.write_string('.')\n\t\t}\n\t}\n\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) embedded_definition_documentation(element psi.EmbeddedDefinition) ? {\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('embedded ')\n\n\tif owner := element.owner() {\n\t\tif owner is psi.PsiNamedElement {\n\t\t\tp.sb.write_string(owner.name())\n\t\t\tp.sb.write_string('.')\n\t\t}\n\t}\n\n\tp.sb.write_string(element.name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) enum_field_documentation(element psi.EnumFieldDeclaration) ? {\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('enum ')\n\n\tif owner := element.owner() {\n\t\tp.sb.write_string(owner.name())\n\t\tp.sb.write_string('.')\n\t}\n\n\tp.sb.write_string(element.name())\n\n\tp.sb.write_string(' = ')\n\n\tp.sb.write_string(element.value_presentation(true))\n\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) receiver_documentation(element psi.Receiver) ? {\n\tp.sb.write_string('Method **receiver**\\n')\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.mutability_modifiers() {\n\t\tp.write_mutability_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string(element.name())\n\tp.sb.write_string(' ')\n\tp.sb.write_string(element.get_type().readable_name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) type_alias_documentation(element psi.TypeAliasDeclaration) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tif modifiers := element.visibility_modifiers() {\n\t\tp.write_visibility_modifiers(modifiers)\n\t\tp.sb.write_string(' ')\n\t}\n\tp.sb.write_string('type ')\n\tp.sb.write_string(element.name())\n\tp.write_generic_parameters(element)\n\tp.sb.write_string(' = ')\n\n\tfor index, type_ in element.types() {\n\t\tp.sb.write_string(psi.convert_type(type_).readable_name())\n\t\tif index < element.types().len - 1 {\n\t\t\tp.sb.write_string(' | ')\n\t\t}\n\t}\n\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n\tp.write_separator()\n\tp.sb.write_string(element.doc_comment())\n}\n\nfn (mut p Provider) generic_parameter_documentation(element psi.GenericParameter) ? {\n\tp.write_module_name(element.containing_file)\n\tp.sb.write_string('```v\\n')\n\tp.sb.write_string('generic parameter ')\n\tp.sb.write_string(element.name())\n\tp.sb.write_string('\\n')\n\tp.sb.write_string('```')\n}\n\nfn (mut p Provider) write_separator() {\n\tp.sb.write_string('\\n\\n')\n}\n\nfn (mut p Provider) write_signature(signature psi.Signature) {\n\tp.sb.write_string(signature.get_text())\n}\n\nfn (mut p Provider) write_mutability_modifiers(modifiers psi.MutabilityModifiers) {\n\tp.sb.write_string(modifiers.get_text())\n}\n\nfn (mut p Provider) write_visibility_modifiers(modifiers psi.VisibilityModifiers) {\n\tp.sb.write_string(modifiers.get_text())\n}\n\nfn (mut p Provider) write_module_name(file ?&psi.PsiFile) {\n\tf := file or { return }\n\tfqn := f.module_fqn()\n\tname := if fqn.len == 0 {\n\t\tf.module_name() or { '' }\n\t} else {\n\t\tfqn\n\t}\n\n\tif name != '' {\n\t\tp.sb.write_string('Module: **${name}**\\n')\n\t}\n}\n\nfn (mut p Provider) write_generic_parameters(element psi.GenericParametersOwner) {\n\tparameters := element.generic_parameters() or { return }\n\tp.sb.write_string(parameters.text_presentation())\n}\n\nfn (mut p Provider) write_attributes(element psi.PsiElement) {\n\tattributes := element.find_child_by_type_or_stub(.attributes) or { return }\n\tattribute_list := attributes.find_children_by_type_or_stub(.attribute)\n\tif attribute_list.len == 0 {\n\t\treturn\n\t}\n\n\tfor attr in attribute_list {\n\t\tp.sb.write_string(attr.get_text())\n\t\tp.sb.write_string('\\n')\n\t}\n}\n\npub fn (mut p Provider) find_documentation_element(element psi.PsiElement) ?psi.PsiElement {\n\tif element is psi.Identifier {\n\t\tparent := element.parent()?\n\t\tif parent is psi.ReferenceExpressionBase {\n\t\t\treturn parent.resolve() or {\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'name': element.get_text()\n\t\t\t\t}).log(.warn, 'Cannot resolve reference for documentation')\n\t\t\t\treturn element\n\t\t\t}\n\t\t}\n\n\t\tif parent is psi.PsiNamedElement {\n\t\t\treturn parent as psi.PsiElement\n\t\t}\n\n\t\tif parent is psi.ImportName {\n\t\t\tif import_spec := parent.parent_nth(2) {\n\t\t\t\tif import_spec is psi.ImportSpec {\n\t\t\t\t\treturn import_spec\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif parent is psi.ImportAlias {\n\t\t\tif import_spec := parent.parent() {\n\t\t\t\tif import_spec is psi.ImportSpec {\n\t\t\t\t\treturn import_spec\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element\n}\n"
  },
  {
    "path": "src/server/features_code_actions.v",
    "content": "module server\n\nimport lsp\nimport json\nimport server.intentions\n\npub fn (mut ls LanguageServer) code_actions(params lsp.CodeActionParams) ?[]lsp.CodeAction {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\tmut actions := []lsp.CodeAction{}\n\n\tctx := intentions.IntentionContext.from(file.psi_file, params.range.start)\n\n\tfor _, mut intention in ls.intentions {\n\t\tif !intention.is_available(ctx) {\n\t\t\tcontinue\n\t\t}\n\n\t\tactions << lsp.CodeAction{\n\t\t\ttitle:   intention.name\n\t\t\tkind:    lsp.refactor\n\t\t\tcommand: lsp.Command{\n\t\t\t\ttitle:     intention.name\n\t\t\t\tcommand:   intention.id\n\t\t\t\targuments: [\n\t\t\t\t\tjson.encode(IntentionData{\n\t\t\t\t\t\tfile_uri: uri\n\t\t\t\t\t\tposition: params.range.start\n\t\t\t\t\t}),\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, mut intention in ls.compiler_quick_fixes {\n\t\tif !intention.is_available(ctx) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !params.context.diagnostics.any(intention.is_matched_message(it.message)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tactions << lsp.CodeAction{\n\t\t\ttitle:   intention.name\n\t\t\tkind:    lsp.quick_fix\n\t\t\tcommand: lsp.Command{\n\t\t\t\ttitle:     intention.name\n\t\t\t\tcommand:   intention.id\n\t\t\t\targuments: [\n\t\t\t\t\tjson.encode(IntentionData{\n\t\t\t\t\t\tfile_uri: uri\n\t\t\t\t\t\tposition: params.range.start\n\t\t\t\t\t}),\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn actions\n}\n"
  },
  {
    "path": "src/server/features_code_lens.v",
    "content": "module server\n\nimport lsp\nimport server.code_lens\n\npub fn (mut ls LanguageServer) code_lens(params lsp.CodeLensParams) ?[]lsp.CodeLens {\n\tif !ls.cfg.code_lens.enable {\n\t\treturn []\n\t}\n\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\tmut visitor := code_lens.new_visitor(ls.cfg.code_lens, uri, file.psi_file)\n\tvisitor.accept(file.psi_file.root())\n\treturn visitor.result()\n}\n"
  },
  {
    "path": "src/server/features_completion.v",
    "content": "module server\n\nimport lsp\nimport analyzer.psi\nimport server.completion\nimport server.completion.providers\nimport loglib\n\npub fn (mut ls LanguageServer) completion(params lsp.CompletionParams) ![]lsp.CompletionItem {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or { return [] }\n\n\toffset := file.find_offset(params.position)\n\n\tmut source := file.psi_file.source_text\n\n\tif offset >= source.len {\n\t\tloglib.with_fields({\n\t\t\t'offset':     offset.str()\n\t\t\t'source_len': source.len.str()\n\t\t}).warn('Offset is out of range')\n\t\treturn []\n\t}\n\n\t// The idea behind this solution is:\n\t// When we have an expression like `foo.` and we want to get the autocompletion variants,\n\t// it can be difficult to directly try to figure out what is before the dot, since the\n\t// parser does not parse it correctly, since there must be an identifier after the dot.\n\t// The idea is that we add some dummy identifier at the cursor point and call go to definition,\n\t// which goes through all the variants that may be for this place.\n\t// Thus, we collect them, filter and show them to the user.\n\tsource = insert_to_string(source, offset, completion.dummy_identifier)\n\n\tres := ls.main_parser.parse_code(source)\n\tmut patched_psi_file := psi.new_psi_file(uri.path(), res.tree, res.source_text)\n\tdefer { patched_psi_file.free() }\n\n\telement := patched_psi_file.root().find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn []\n\t}\n\n\t// We use CompletionContext in order not to calculate the current partial context\n\t// in each provider, but to calculate it once and pass it to all providers.\n\tmut ctx := &completion.CompletionContext{\n\t\telement:      element\n\t\tposition:     params.position\n\t\toffset:       offset\n\t\ttrigger_kind: params.context.trigger_kind\n\t}\n\tctx.compute()\n\n\tmut result_set := &completion.CompletionResultSet{}\n\n\tmut processor := &providers.ReferenceCompletionProcessor{\n\t\tfile:       file.psi_file\n\t\tmodule_fqn: file.psi_file.module_fqn()\n\t\troot:       ls.root_uri.path()\n\t\tctx:        ctx\n\t}\n\n\tmut completion_providers := []completion.CompletionProvider{}\n\tcompletion_providers << providers.ReferenceCompletionProvider{\n\t\tprocessor: processor\n\t}\n\tcompletion_providers << providers.ModulesImportProvider{}\n\tcompletion_providers << providers.ReturnCompletionProvider{}\n\tcompletion_providers << providers.CompileTimeConstantCompletionProvider{}\n\tcompletion_providers << providers.InitsCompletionProvider{}\n\tcompletion_providers << providers.KeywordsCompletionProvider{}\n\tcompletion_providers << providers.TopLevelCompletionProvider{}\n\tcompletion_providers << providers.LoopKeywordsCompletionProvider{}\n\tcompletion_providers << providers.PureBlockExpressionCompletionProvider{}\n\tcompletion_providers << providers.PureBlockStatementCompletionProvider{}\n\tcompletion_providers << providers.OrBlockExpressionCompletionProvider{}\n\tcompletion_providers << providers.FunctionLikeCompletionProvider{}\n\tcompletion_providers << providers.AssertCompletionProvider{}\n\tcompletion_providers << providers.ModuleNameCompletionProvider{}\n\tcompletion_providers << providers.NilKeywordCompletionProvider{}\n\tcompletion_providers << providers.JsonAttributeCompletionProvider{}\n\tcompletion_providers << providers.AttributesCompletionProvider{}\n\tcompletion_providers << providers.ImportsCompletionProvider{}\n\n\tfor mut provider in completion_providers {\n\t\tif !provider.is_available(ctx) {\n\t\t\tcontinue\n\t\t}\n\t\tprovider.add_completion(ctx, mut result_set)\n\t}\n\n\tfor el in processor.elements() {\n\t\tresult_set.add_element(el)\n\t}\n\n\t// unsafe { res.tree.free() }\n\n\treturn result_set.elements()\n}\n\nfn insert_to_string(str string, offset u32, insert string) string {\n\treturn str[..offset] + insert + str[offset..]\n}\n"
  },
  {
    "path": "src/server/features_definition.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport analyzer.psi\nimport server.tform\n\npub fn (mut ls LanguageServer) definition(params lsp.TextDocumentPositionParams) ?[]lsp.LocationLink {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_reference_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find reference')\n\t\treturn none\n\t}\n\n\tresolved_elements := element.reference().multi_resolve()\n\tif resolved_elements.len == 0 {\n\t\treturn none\n\t}\n\n\tmut links := []lsp.LocationLink{cap: resolved_elements.len}\n\n\tfor resolved in resolved_elements {\n\t\tcontaining_file := resolved.containing_file() or { continue }\n\t\tif data := new_resolve_result(containing_file, resolved) {\n\t\t\tlinks << data.to_location_link(element.text_range())\n\t\t}\n\t}\n\n\treturn links\n}\n\nstruct ResolveResult {\npub:\n\tfilepath string\n\tname     string\n\trange    psi.TextRange\n}\n\npub fn new_resolve_result(containing_file &psi.PsiFile, element psi.PsiElement) ?ResolveResult {\n\tif element is psi.PsiNamedElement {\n\t\ttext_range := element.identifier_text_range()\n\t\treturn ResolveResult{\n\t\t\trange:    text_range\n\t\t\tfilepath: containing_file.path()\n\t\t\tname:     element.name()\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn (r &ResolveResult) to_location_link(origin_selection_range psi.TextRange) lsp.LocationLink {\n\trange := tform.text_range_to_lsp_range(r.range)\n\treturn lsp.LocationLink{\n\t\ttarget_uri:             lsp.document_uri_from_path(r.filepath)\n\t\torigin_selection_range: tform.text_range_to_lsp_range(origin_selection_range)\n\t\ttarget_range:           range\n\t\ttarget_selection_range: range\n\t}\n}\n"
  },
  {
    "path": "src/server/features_did_change.v",
    "content": "module server\n\nimport lsp\nimport analyzer\nimport time\nimport loglib\n\npub fn (mut ls LanguageServer) did_change(params lsp.DidChangeTextDocumentParams) {\n\turi := params.text_document.uri.normalize()\n\tmut file := ls.opened_files[uri] or {\n\t\tloglib.with_fields({\n\t\t\t'uri':    uri.str()\n\t\t\t'params': params.str()\n\t\t\t'caller': @METHOD\n\t\t}).error('File not opened')\n\t\treturn\n\t}\n\tnew_content := params.content_changes[0].text\n\tfile.psi_file.reparse(new_content, mut ls.main_parser)\n\tls.opened_files[uri] = analyzer.OpenedFile{\n\t\turi:      uri\n\t\tversion:  file.version++\n\t\tpsi_file: file.psi_file\n\t}\n\n\tls.indexing_mng.indexer.mark_as_dirty(uri.path(), new_content) or {\n\t\tloglib.with_fields({\n\t\t\t'uri':    uri.str()\n\t\t\t'params': params.str()\n\t\t\t'caller': @METHOD\n\t\t\t'err':    err.str()\n\t\t}).error('Error marking document as dirty')\n\t}\n\n\twatch := time.new_stopwatch(auto_start: true)\n\tls.indexing_mng.update_stub_indexes([file.psi_file])\n\n\ttype_cache.clear()\n\tresolve_cache.clear()\n\tenum_fields_cache = map[string]int{}\n\n\tloglib.with_fields({\n\t\t'caller':   @METHOD\n\t\t'duration': watch.elapsed().str()\n\t}).info('Updated stub indexes')\n\n\tloglib.with_fields({\n\t\t'uri': uri.str()\n\t}).info('Reparsed file')\n}\n"
  },
  {
    "path": "src/server/features_did_change_watched_files.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport os\n\npub fn (mut ls LanguageServer) did_change_watched_files(params lsp.DidChangeWatchedFilesParams) {\n\tchanges := params.changes\n\tmut is_rename := false\n\tmut structure_changed := false\n\n\t// NOTE:\n\t// 1. Renaming a file returns two events: one \"created\" event for the\n\t//    same file with new name and one \"deleted\" event for the file with\n\t//    old name.\n\t// 2. Deleting a folder does not trigger a \"deleted\" event. Restoring\n\t//    the files of the folder however triggers the \"created\" event.\n\t// 3. Renaming a folder triggers the \"created\" event for each file\n\t//    but with no \"deleted\" event prior to it.\n\tfor i, change in changes {\n\t\tchange_uri := change.uri.normalize()\n\n\t\tfilename := os.file_name(change_uri.path())\n\t\tif filename == 'v.mod' || filename == '.git' {\n\t\t\tstructure_changed = true\n\t\t}\n\n\t\tmatch change.typ {\n\t\t\t.created {\n\t\t\t\tif next_change := changes[i + 1] {\n\t\t\t\t\tis_rename = next_change.typ == .deleted\n\t\t\t\t}\n\n\t\t\t\tif is_rename {\n\t\t\t\t\tprev_change := changes[i + 1] or { continue }\n\t\t\t\t\tprev_uri := prev_change.uri.normalize()\n\t\t\t\t\tif file_index := ls.indexing_mng.indexer.rename_file(prev_uri.path(),\n\t\t\t\t\t\tchange_uri.path())\n\t\t\t\t\t{\n\t\t\t\t\t\tif isnil(file_index.sink) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tls.indexing_mng.update_stub_indexes_from_sinks([*file_index.sink])\n\n\t\t\t\t\t\tloglib.with_fields({\n\t\t\t\t\t\t\t'old': prev_uri.path()\n\t\t\t\t\t\t\t'new': change_uri.path()\n\t\t\t\t\t\t}).info('Renamed file')\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif file_index := ls.indexing_mng.indexer.add_file(change_uri.path()) {\n\t\t\t\t\t\tif isnil(file_index.sink) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tls.indexing_mng.update_stub_indexes_from_sinks([*file_index.sink])\n\n\t\t\t\t\t\tloglib.with_fields({\n\t\t\t\t\t\t\t'file': change_uri.path()\n\t\t\t\t\t\t}).info('Added file')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t.deleted {\n\t\t\t\tif is_rename {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif file_index := ls.indexing_mng.indexer.remove_file(change_uri.path()) {\n\t\t\t\t\tif isnil(file_index.sink) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tls.indexing_mng.update_stub_indexes_from_sinks([*file_index.sink])\n\n\t\t\t\t\tloglib.with_fields({\n\t\t\t\t\t\t'file': change_uri.path()\n\t\t\t\t\t}).info('Removed file')\n\t\t\t\t}\n\t\t\t}\n\t\t\t.changed {}\n\t\t}\n\n\t\tls.client.log_message(change.str(), .info)\n\t}\n\n\tif structure_changed {\n\t\tloglib.info('Project structure changed, clearing project root cache')\n\t\tls.project_resolver.clear()\n\n\t\tfor uri, _ in ls.opened_files {\n\t\t\tls.run_diagnostics_in_bg(uri)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/server/features_did_close.v",
    "content": "module server\n\nimport lsp\nimport loglib\n\npub fn (mut ls LanguageServer) did_close(params lsp.DidCloseTextDocumentParams) {\n\turi := params.text_document.uri.normalize()\n\tif mut file := ls.opened_files[uri] {\n\t\tfile.psi_file.free()\n\t}\n\n\tls.opened_files.delete(uri)\n\n\tloglib.with_fields({\n\t\t'uri':              uri.str()\n\t\t'opened_files len': ls.opened_files.len.str()\n\t}).info('closed file')\n}\n"
  },
  {
    "path": "src/server/features_did_open.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport analyzer\nimport analyzer.psi\n\npub fn (mut ls LanguageServer) did_open(params lsp.DidOpenTextDocumentParams) {\n\tsrc := params.text_document.text\n\turi := params.text_document.uri.normalize()\n\n\tres := ls.main_parser.parse_code(src)\n\tpsi_file := psi.new_psi_file(uri.path(), res.tree, res.source_text)\n\n\tls.opened_files[uri] = analyzer.OpenedFile{\n\t\turi:      uri\n\t\tversion:  0\n\t\tpsi_file: psi_file\n\t}\n\n\tif 'no-diagnostics' !in ls.initialization_options {\n\t\tls.run_diagnostics_in_bg(uri)\n\t}\n\n\t// Useful for debugging\n\t//\n\t// mut visitor := psi.PrinterVisitor{}\n\t// psi_file.root().accept_mut(mut visitor)\n\t// visitor.print()\n\t//\n\t// tree := index.build_stub_tree(psi_file, '')\n\t// tree.print()\n\n\tloglib.with_fields({\n\t\t'uri':              uri.str()\n\t\t'opened_files len': ls.opened_files.len.str()\n\t}).info('Opened file')\n}\n"
  },
  {
    "path": "src/server/features_did_save.v",
    "content": "module server\n\nimport lsp\n\npub fn (mut ls LanguageServer) did_save(params lsp.DidSaveTextDocumentParams) {\n\turi := params.text_document.uri.normalize()\n\tls.run_diagnostics_in_bg(uri)\n}\n"
  },
  {
    "path": "src/server/features_document_highlight.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport server.tform\nimport analyzer.psi\nimport analyzer.psi.search\n\npub fn (mut ls LanguageServer) document_highlight(params lsp.TextDocumentPositionParams) ?[]lsp.DocumentHighlight {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'caller': @METHOD\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn []\n\t}\n\n\treferences := search.references(element, include_declaration: true, only_in_current_file: true)\n\n\tmut highlights := []lsp.DocumentHighlight{}\n\tfor reference in references {\n\t\trange := if reference is psi.PsiNamedElement {\n\t\t\treference.identifier_text_range()\n\t\t} else {\n\t\t\treference.text_range()\n\t\t}\n\t\thighlights << lsp.DocumentHighlight{\n\t\t\trange: tform.text_range_to_lsp_range(range)\n\t\t\tkind:  read_write_kind(reference)\n\t\t}\n\t}\n\n\treturn highlights\n}\n\n// read_write_kind returns the kind of the highlight for the given element.\n//\n// - `DocumentHighlightKind.read` means that the highlight is a read access,\n// - `DocumentHighlightKind.write` means that the highlight is a write access.\n// - `DocumentHighlightKind.text` means that the highlight is neither a read nor a write access.\nfn read_write_kind(element psi.PsiElement) lsp.DocumentHighlightKind {\n\tparent := element.parent() or { return .text }\n\n\tif element is psi.VarDefinition || element is psi.ConstantDefinition\n\t\t|| element is psi.ParameterDeclaration || element is psi.Receiver\n\t\t|| element is psi.FieldDeclaration || element is psi.EnumFieldDeclaration {\n\t\t// for parameter/receiver not an actual write, but we want to highlight it\n\t\t// with different color than read access.\n\t\treturn .write\n\t}\n\n\tif parent.element_type() == .expression_list {\n\t\tgrand := parent.parent() or { return .text }\n\t\tif grand.element_type() == .assignment_statement {\n\t\t\tleft := grand.first_child() or { return .text }\n\t\t\tif left.is_parent_of(element) {\n\t\t\t\treturn .write\n\t\t\t}\n\t\t\treturn .read\n\t\t}\n\t}\n\n\tif parent.element_type() in [.send_statement, .append_statement] {\n\t\tleft := parent.first_child() or { return .text }\n\t\tif left.is_parent_of(element) {\n\t\t\treturn .write\n\t\t}\n\t\treturn .read\n\t}\n\n\tif parent.element_type() in [.send_statement, .append_statement, .field_name] {\n\t\treturn .write\n\t}\n\n\treturn .read\n}\n"
  },
  {
    "path": "src/server/features_document_symbol.v",
    "content": "module server\n\nimport lsp\nimport analyzer.psi\nimport server.tform\n\npub fn (mut ls LanguageServer) document_symbol(params lsp.DocumentSymbolParams) ![]lsp.DocumentSymbol {\n\turi := params.text_document.uri.normalize()\n\tmut file_symbols := []lsp.DocumentSymbol{}\n\n\telements := stubs_index.get_all_elements_from_file(uri.path())\n\tfor element in elements {\n\t\tfile_symbols << document_symbol_presentation(element) or { continue }\n\t}\n\n\treturn file_symbols\n}\n\nfn document_symbol_presentation(element psi.PsiElement) ?lsp.DocumentSymbol {\n\tfull_text_range := element.text_range()\n\tif element is psi.PsiNamedElement {\n\t\tif element.name() == '' {\n\t\t\treturn none\n\t\t}\n\n\t\tidentifier_text_range := element.identifier_text_range()\n\t\tchildren := symbol_children(element)\n\t\treturn lsp.DocumentSymbol{\n\t\t\tname:            name_presentation(element)\n\t\t\tdetail:          detail_presentation(element)\n\t\t\tkind:            symbol_kind(element as psi.PsiElement)?\n\t\t\trange:           tform.text_range_to_lsp_range(full_text_range)\n\t\t\tselection_range: tform.text_range_to_lsp_range(identifier_text_range)\n\t\t\tchildren:        children\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn symbol_kind(element psi.PsiElement) ?lsp.SymbolKind {\n\tmatch element {\n\t\tpsi.FunctionOrMethodDeclaration {\n\t\t\tif _ := element.receiver() {\n\t\t\t\treturn .method\n\t\t\t}\n\t\t\treturn .function\n\t\t}\n\t\tpsi.StructDeclaration {\n\t\t\treturn .struct_\n\t\t}\n\t\tpsi.InterfaceDeclaration {\n\t\t\treturn .interface_\n\t\t}\n\t\tpsi.InterfaceMethodDeclaration {\n\t\t\treturn .method\n\t\t}\n\t\tpsi.FieldDeclaration {\n\t\t\treturn .field\n\t\t}\n\t\tpsi.EnumDeclaration {\n\t\t\treturn .enum_\n\t\t}\n\t\tpsi.EnumFieldDeclaration {\n\t\t\treturn .enum_member\n\t\t}\n\t\tpsi.ConstantDefinition {\n\t\t\treturn .constant\n\t\t}\n\t\tpsi.TypeAliasDeclaration {\n\t\t\treturn .type_parameter\n\t\t}\n\t\telse {}\n\t}\n\n\treturn none\n}\n\nfn name_presentation(element psi.PsiNamedElement) string {\n\tname := element.name()\n\n\tif element is psi.FunctionOrMethodDeclaration {\n\t\tmut parts := []string{}\n\n\t\tif receiver := element.receiver() {\n\t\t\tparts << receiver.get_text()\n\t\t}\n\n\t\tparts << name\n\n\t\tif parameters := element.generic_parameters() {\n\t\t\tparts << parameters.text_presentation()\n\t\t}\n\n\t\treturn parts.join(' ')\n\t}\n\tif element is psi.GenericParametersOwner {\n\t\tparameters := element.generic_parameters() or { return name }\n\t\treturn name + parameters.text_presentation()\n\t}\n\treturn name\n}\n\nfn detail_presentation(element psi.PsiNamedElement) string {\n\tif element is psi.FunctionOrMethodDeclaration {\n\t\tif signature := element.signature() {\n\t\t\treturn 'fn ' + signature.get_text()\n\t\t}\n\t}\n\tif element is psi.FieldDeclaration {\n\t\treturn element.get_type().readable_name()\n\t}\n\tif element is psi.InterfaceMethodDeclaration {\n\t\tif signature := element.signature() {\n\t\t\treturn signature.get_text()\n\t\t}\n\t}\n\tif element is psi.ConstantDefinition {\n\t\treturn element.get_type().readable_name()\n\t}\n\tif element is psi.EnumFieldDeclaration {\n\t\treturn '= ' + element.value_presentation(true)\n\t}\n\treturn ''\n}\n\nfn symbol_children(element psi.PsiNamedElement) []lsp.DocumentSymbol {\n\tmut children := []psi.PsiElement{}\n\tif element is psi.StructDeclaration {\n\t\tchildren << element.own_fields()\n\t} else if element is psi.EnumDeclaration {\n\t\tchildren << element.fields()\n\t} else if element is psi.InterfaceDeclaration {\n\t\tchildren << element.fields()\n\t\tchildren << element.methods()\n\t}\n\n\tmut symbols := []lsp.DocumentSymbol{cap: children.len}\n\tfor child in children {\n\t\tsymbols << document_symbol_presentation(child) or { continue }\n\t}\n\treturn symbols\n}\n"
  },
  {
    "path": "src/server/features_execute_command.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport json\nimport server.intentions\n\npub struct IntentionData {\npub:\n\tfile_uri string\n\tposition lsp.Position\n}\n\npub fn (mut ls LanguageServer) execute_command(params lsp.ExecuteCommandParams) ? {\n\tmut intention := ls.find_intention_or_quickfix(params.command)?\n\n\targuments := json.decode([]string, params.arguments) or { []string{} }\n\n\targument := json.decode(IntentionData, arguments[0]) or {\n\t\tloglib.with_fields({\n\t\t\t'command':  params.command\n\t\t\t'argument': params.arguments\n\t\t}).warn('Got invalid argument')\n\t\treturn\n\t}\n\n\tfile_uri := argument.file_uri\n\tfile := ls.get_file(file_uri)?\n\tpos := argument.position\n\n\tctx := intentions.IntentionContext.from(file.psi_file, pos)\n\tedits := intention.invoke(ctx) or { return }\n\n\tls.client.apply_edit(edit: edits)\n}\n\npub fn (mut ls LanguageServer) find_intention_or_quickfix(name string) ?intentions.Intention {\n\tif i := ls.intentions[name] {\n\t\treturn i\n\t}\n\n\tif qf := ls.compiler_quick_fixes[name] {\n\t\treturn qf as intentions.Intention\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/server/features_folding_range.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport server.folding\n\npub fn (mut ls LanguageServer) folding_range(params lsp.FoldingRangeParams) ?[]lsp.FoldingRange {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or {\n\t\tloglib.with_fields({\n\t\t\t'uri': uri.str()\n\t\t}).warn('Folding range requested for unopened file')\n\t\treturn []\n\t}\n\n\tmut visitor := folding.FoldingVisitor.new(file.psi_file)\n\tranges := visitor.accept(file.psi_file.root())\n\n\treturn ranges\n}\n"
  },
  {
    "path": "src/server/features_formatting.v",
    "content": "module server\n\nimport lsp\nimport os\nimport server.tform\nimport loglib\n\nconst temp_formatting_file_path = os.join_path(os.temp_dir(), 'v-analyzer-formatting-temp.v')\n\npub fn (mut ls LanguageServer) formatting(params lsp.DocumentFormattingParams) ![]lsp.TextEdit {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or { return error('Cannot format not opened file') }\n\n\tos.write_file(temp_formatting_file_path, file.psi_file.source_text) or {\n\t\treturn error('Cannot write temp file for formatting: ${err}')\n\t}\n\n\tloglib.with_fields({\n\t\t'uri': file.uri.str()\n\t}).info('Formatting file')\n\n\tmut fmt_proc := ls.launch_tool('fmt', os.norm_path(temp_formatting_file_path))!\n\tdefer {\n\t\tfmt_proc.close()\n\t}\n\tfmt_proc.run()\n\n\t// read entire output until EOF\n\tmut output := fmt_proc.stdout_slurp()\n\tfmt_proc.wait()\n\n\tloglib.with_fields({\n\t\t'code':   fmt_proc.code.str()\n\t\t'status': fmt_proc.status.str()\n\t}).info('Formatting finished')\n\n\t$if windows {\n\t\toutput = output.replace('\\r\\r', '\\r')\n\t}\n\n\tif fmt_proc.code != 0 && fmt_proc.status == .exited {\n\t\terrors := fmt_proc.stderr_slurp().trim_space()\n\t\tls.client.show_message(errors, .info)\n\t\treturn error('Formatting failed: ${errors}')\n\t\t// return []\n\t}\n\n\treturn [\n\t\tlsp.TextEdit{\n\t\t\trange:    tform.text_range_to_lsp_range(file.psi_file.root().text_range())\n\t\t\tnew_text: output\n\t\t},\n\t]\n}\n"
  },
  {
    "path": "src/server/features_formatting_test.v",
    "content": "module server\n\nimport lsp\nimport os\nimport analyzer\nimport analyzer.psi\nimport analyzer.parser\n\nfn test_large_file() {\n\ttest_file := os.real_path(@VMODROOT + '/src/server/general.v')\n\n\tsrc := os.read_file(test_file) or { panic('Cannot read file') }\n\n\tmut ls := LanguageServer.new(analyzer.IndexingManager.new())\n\tls.setup_toolchain()\n\tls.setup_vpaths()\n\n\turi := lsp.document_uri_from_path(test_file)\n\n\tmut p := parser.Parser.new()\n\tdefer { p.free() }\n\tres := p.parse_code(src)\n\tpsi_file := psi.new_psi_file(uri.path(), res.tree, res.source_text)\n\tls.opened_files[uri] = analyzer.OpenedFile{\n\t\turi:      uri\n\t\tversion:  0\n\t\tpsi_file: psi_file\n\t}\n\n\tparams := lsp.DocumentFormattingParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: uri\n\t\t}\n\t}\n\n\ttext_edit_result := ls.formatting(params) or { panic('Cannot format file') }\n\tassert text_edit_result.len == 1\n}\n"
  },
  {
    "path": "src/server/features_hover.v",
    "content": "module server\n\nimport lsp\nimport server.documentation\nimport loglib\nimport server.tform\n\npub fn (mut ls LanguageServer) hover(params lsp.HoverParams) ?lsp.Hover {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\tloglib.with_fields({\n\t\t'position': params.position.str()\n\t\t'uri':      file.uri\n\t}).warn('Hover request')\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn none\n\t}\n\n\tif element.element_type() == .unknown {\n\t\tmut provider := documentation.KeywordProvider{}\n\t\tif content := provider.documentation(element) {\n\t\t\treturn lsp.Hover{\n\t\t\t\tcontents: lsp.hover_markdown_string(content)\n\t\t\t\trange:    tform.text_range_to_lsp_range(element.text_range())\n\t\t\t}\n\t\t}\n\t}\n\n\tmut provider := documentation.Provider{}\n\tdoc_element := provider.find_documentation_element(element)?\n\tif content := provider.documentation(doc_element) {\n\t\treturn lsp.Hover{\n\t\t\tcontents: lsp.hover_markdown_string(content)\n\t\t\trange:    tform.text_range_to_lsp_range(element.text_range())\n\t\t}\n\t}\n\n\t$if show_ast_on_hover ? {\n\t\t// Show AST tree for debugging purposes.\n\t\tif grand := element.parent_nth(2) {\n\t\t\tparent := element.parent()?\n\t\t\tthis := element.type_name() + ': ' + element.node().type_name.str()\n\t\t\tparent_elem := parent.type_name() + ': ' + parent.node().type_name.str()\n\t\t\tgrand_elem := grand.type_name() + ': ' + grand.node().type_name.str()\n\t\t\treturn lsp.Hover{\n\t\t\t\tcontents: lsp.hover_markdown_string('```\\n' + grand_elem + '\\n  ' + parent_elem +\n\t\t\t\t\t'\\n   ' + this + '\\n```')\n\t\t\t\trange:    tform.text_range_to_lsp_range(element.text_range())\n\t\t\t}\n\t\t}\n\n\t\treturn lsp.Hover{\n\t\t\tcontents: lsp.hover_markdown_string(element.type_name() + ': ' +\n\t\t\t\telement.node().type_name.str())\n\t\t\trange:    tform.text_range_to_lsp_range(element.text_range())\n\t\t}\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/server/features_implementation.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport server.tform\nimport analyzer.psi\nimport analyzer.psi.search\n\npub fn (mut ls LanguageServer) implementation(params lsp.TextDocumentPositionParams) ?[]lsp.Location {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn none\n\t}\n\n\tif method := element.parent_of_type(.interface_method_definition) {\n\t\tif method is psi.InterfaceMethodDeclaration {\n\t\t\tmethods := search.implementation_methods(*method)\n\t\t\treturn tform.elements_to_locations(methods)\n\t\t}\n\t}\n\n\tif interface_declaration := element.parent_of_type(.interface_declaration) {\n\t\tif interface_declaration is psi.InterfaceDeclaration {\n\t\t\timplementations := search.implementations(*interface_declaration)\n\t\t\treturn tform.elements_to_locations(implementations)\n\t\t}\n\t}\n\n\tif struct_declaration := element.parent_of_type(.struct_declaration) {\n\t\tif struct_declaration is psi.StructDeclaration {\n\t\t\tsupers := search.supers(*struct_declaration)\n\t\t\treturn tform.elements_to_locations(supers)\n\t\t}\n\t}\n\n\tif method := element.parent_of_type(.function_declaration) {\n\t\tif method is psi.FunctionOrMethodDeclaration {\n\t\t\tsuper_methods := search.super_methods(*method)\n\t\t\treturn tform.elements_to_locations(super_methods)\n\t\t}\n\t}\n\n\tloglib.with_fields({\n\t\t'element':      element.get_text()\n\t\t'text_range':   element.text_range().str()\n\t\t'element_type': element.element_type().str()\n\t}).warn('Element is not inside an interface or struct declaration')\n\n\treturn none\n}\n"
  },
  {
    "path": "src/server/features_inlay_hints.v",
    "content": "module server\n\nimport lsp\nimport server.hints\n\npub fn (mut ls LanguageServer) inlay_hints(params lsp.InlayHintParams) ?[]lsp.InlayHint {\n\tif !ls.cfg.inlay_hints.enable {\n\t\treturn none\n\t}\n\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\tmut visitor := hints.InlayHintsVisitor{\n\t\tcfg: ls.cfg.inlay_hints\n\t}\n\tvisitor.accept(file.psi_file.root())\n\treturn visitor.result\n}\n"
  },
  {
    "path": "src/server/features_prepare_rename.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport analyzer.psi\nimport server.tform\n\npub fn (mut ls LanguageServer) prepare_rename(params lsp.PrepareRenameParams) !lsp.PrepareRenameResult {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or { return error('cannot rename element from not opened file') }\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn error('cannot find element at ' + offset.str())\n\t}\n\n\tif element !is psi.Identifier {\n\t\treturn error('cannot rename non identifier element')\n\t}\n\n\tresolved := resolve_identifier(element)\n\tif resolved !is psi.VarDefinition {\n\t\treturn error('cannot rename non-variable element')\n\t}\n\n\tif resolved is psi.PsiNamedElement {\n\t\telement_text_range := resolved.identifier_text_range()\n\n\t\treturn lsp.PrepareRenameResult{\n\t\t\trange:       tform.text_range_to_lsp_range(element_text_range)\n\t\t\tplaceholder: ''\n\t\t}\n\t}\n\n\treturn error('')\n}\n\nfn resolve_identifier(element psi.PsiElement) psi.PsiElement {\n\tparent := element.parent() or { return element }\n\tresolved := if parent is psi.ReferenceExpression {\n\t\tparent.resolve() or { return element }\n\t} else if parent is psi.TypeReferenceExpression {\n\t\tparent.resolve() or { return element }\n\t} else {\n\t\tparent\n\t}\n\n\treturn resolved\n}\n"
  },
  {
    "path": "src/server/features_references.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport server.tform\nimport analyzer.psi.search\n\npub fn (mut ls LanguageServer) references(params lsp.ReferenceParams) []lsp.Location {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or { return [] }\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn []\n\t}\n\n\treferences := search.references(element)\n\treturn tform.elements_to_locations(references)\n}\n"
  },
  {
    "path": "src/server/features_rename.v",
    "content": "module server\n\nimport lsp\nimport loglib\nimport server.tform\nimport analyzer.psi.search\n\npub fn (mut ls LanguageServer) rename(params lsp.RenameParams) !lsp.WorkspaceEdit {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri) or { return error('cannot rename element from not opened file') }\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn error('cannot find element at ' + offset.str())\n\t}\n\n\treferences := search.references(element, include_declaration: true)\n\tedits := tform.elements_to_text_edits(references, params.new_name)\n\n\treturn lsp.WorkspaceEdit{\n\t\tchanges: {\n\t\t\turi: edits\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/server/features_semantic_tokens.v",
    "content": "module server\n\nimport lsp\nimport server.semantic\nimport time\n\nconst max_line_for_resolve_semantic_tokens = 1000\nconst max_line_for_any_semantic_tokens = 10000\n\npub fn (mut ls LanguageServer) semantic_tokens(text_document lsp.TextDocumentIdentifier, range lsp.Range) ?lsp.SemanticTokens {\n\tif ls.cfg.enable_semantic_tokens == .none_ {\n\t\treturn none\n\t}\n\n\turi := text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\tlines := file.psi_file.source_text.count('\\n')\n\n\tif lines > max_line_for_any_semantic_tokens {\n\t\t// File too large, don't compute any tokens.\n\t\treturn lsp.SemanticTokens{}\n\t}\n\n\tif lines > max_line_for_resolve_semantic_tokens || ls.cfg.enable_semantic_tokens == .syntax {\n\t\t// We don't want to send too many tokens (and compute it), so we just\n\t\t// send dumb-aware tokens for large files.\n\t\tdumb_aware_visitor := semantic.new_dumb_aware_semantic_visitor(range, file.psi_file)\n\t\ttokens := dumb_aware_visitor.accept(file.psi_file.root)\n\t\treturn lsp.SemanticTokens{\n\t\t\tresult_id: time.now().unix().str()\n\t\t\tdata:      semantic.encode(tokens)\n\t\t}\n\t}\n\n\tmut result := semantic.new_dumb_aware_semantic_visitor(range, file.psi_file)\n\t\t.accept(file.psi_file.root)\n\tresolve_tokens := semantic.new_resolve_semantic_visitor(range, file.psi_file)\n\t\t.accept(file.psi_file.root)\n\n\tresult << resolve_tokens\n\n\treturn lsp.SemanticTokens{\n\t\tresult_id: time.now().unix().str()\n\t\tdata:      semantic.encode(result)\n\t}\n}\n"
  },
  {
    "path": "src/server/features_signature_help.v",
    "content": "module server\n\nimport lsp\nimport analyzer.psi\nimport loglib\n\npub fn (mut ls LanguageServer) signature_help(params lsp.SignatureHelpParams) ?lsp.SignatureHelp {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_element_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find element')\n\t\treturn none\n\t}\n\n\tcall := element.parent_of_type_or_self(.call_expression) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find call expression')\n\t\treturn none\n\t}\n\n\tif call is psi.CallExpression {\n\t\tresolved := call.resolve() or {\n\t\t\tloglib.with_fields({\n\t\t\t\t'offset': offset.str()\n\t\t\t}).warn('Cannot resolve call expression for signature help')\n\t\t\treturn none\n\t\t}\n\n\t\tif resolved is psi.FunctionOrMethodDeclaration {\n\t\t\tctx := params.context\n\t\t\tactive_parameter := call.parameter_index_on_offset(offset)\n\n\t\t\tif ctx.is_retrigger {\n\t\t\t\tmut help := ctx.active_signature_help\n\t\t\t\thelp.active_parameter = active_parameter\n\t\t\t\treturn help\n\t\t\t}\n\n\t\t\tsignature := resolved.signature()?\n\t\t\tparameters := signature.parameters()\n\n\t\t\tmut param_infos := []lsp.ParameterInformation{}\n\t\t\tfor parameter in parameters {\n\t\t\t\tparam_infos << lsp.ParameterInformation{\n\t\t\t\t\tlabel: parameter.get_text()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn lsp.SignatureHelp{\n\t\t\t\tactive_parameter: active_parameter\n\t\t\t\tsignatures:       [\n\t\t\t\t\tlsp.SignatureInformation{\n\t\t\t\t\t\tlabel:      'fn ${resolved.name()}${signature.get_text()}'\n\t\t\t\t\t\tparameters: param_infos\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/server/features_type_definition.v",
    "content": "module server\n\nimport lsp\nimport analyzer.psi\nimport analyzer.psi.types\nimport loglib\n\npub fn (mut ls LanguageServer) type_definition(params lsp.TextDocumentPositionParams) ?[]lsp.LocationLink {\n\turi := params.text_document.uri.normalize()\n\tfile := ls.get_file(uri)?\n\n\toffset := file.find_offset(params.position)\n\telement := file.psi_file.find_reference_at(offset) or {\n\t\tloglib.with_fields({\n\t\t\t'offset': offset.str()\n\t\t}).warn('Cannot find reference')\n\t\treturn none\n\t}\n\n\telement_text_range := element.text_range()\n\n\tresolved := element.resolve() or {\n\t\tloglib.with_fields({\n\t\t\t'caller': @METHOD\n\t\t\t'name':   element.name()\n\t\t}).warn('Cannot resolve reference')\n\t\treturn none\n\t}\n\n\ttyp :=\n\t\ttypes.unwrap_generic_instantiation_type(types.unwrap_pointer_type(psi.infer_type(resolved)))\n\ttype_element := psi.find_element(typ.qualified_name())?\n\n\tcontaining_file := type_element.containing_file() or { return [] }\n\tdata := new_resolve_result(containing_file, type_element) or { return [] }\n\treturn [\n\t\tdata.to_location_link(element_text_range),\n\t]\n}\n"
  },
  {
    "path": "src/server/features_view_stub_tree.v",
    "content": "module server\n\nimport lsp\nimport strings\nimport analyzer.index\n\npub fn (mut ls LanguageServer) view_stub_tree(params lsp.TextDocumentIdentifier) ?string {\n\turi := params.uri.normalize()\n\tfile := ls.get_file(uri) or { return 'file not opened' }\n\n\tmut sb := strings.new_builder(100)\n\ttree := index.build_stub_tree(file.psi_file, params.uri.dir_path())\n\ttree.print_to(mut sb)\n\n\treturn sb.str()\n}\n"
  },
  {
    "path": "src/server/features_workspace_symbol.v",
    "content": "module server\n\nimport lsp\nimport server.tform\nimport analyzer.psi\n\npub fn (mut ls LanguageServer) workspace_symbol(_ lsp.WorkspaceSymbolParams) ?[]lsp.WorkspaceSymbol {\n\tworkspace_elements := ls.indexing_mng.stub_index.get_all_elements_from(.workspace)\n\n\tmut workspace_symbols := []lsp.WorkspaceSymbol{cap: workspace_elements.len}\n\n\tfor elem in workspace_elements {\n\t\tfile := elem.containing_file() or { continue }\n\t\turi := file.uri()\n\t\tmodule_name := file.module_name() or { '' }\n\n\t\tif elem is psi.PsiNamedElement {\n\t\t\tname := elem.name()\n\t\t\tif name == '_' {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfqn := if module_name == '' { name } else { module_name + '.' + name }\n\n\t\t\ttext_range := elem.identifier_text_range()\n\t\t\tworkspace_symbols << lsp.WorkspaceSymbol{\n\t\t\t\tname:     fqn\n\t\t\t\tkind:     symbol_kind(elem as psi.PsiElement) or { continue }\n\t\t\t\tlocation: lsp.Location{\n\t\t\t\t\turi:   uri\n\t\t\t\t\trange: tform.text_range_to_lsp_range(text_range)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn workspace_symbols\n}\n"
  },
  {
    "path": "src/server/file_diff/Diff.v",
    "content": "module file_diff\n\nimport lsp\n\npub struct Edit {\n\trange    lsp.Range\n\tnew_text string\n}\n\npub struct Diff {\n\turi lsp.DocumentUri\nmut:\n\tedits []Edit\n}\n\npub fn Diff.for_file(uri lsp.DocumentUri) Diff {\n\treturn Diff{\n\t\turi: uri\n\t}\n}\n\npub fn (mut diff Diff) append_to_begin(line int, text string) {\n\tdiff.append_to(line, 0, text)\n}\n\npub fn (mut diff Diff) append_to(line int, col int, text string) {\n\tpos := Diff.line_pos(line, col)\n\tdiff.edits << Edit{\n\t\trange:    lsp.Range{\n\t\t\tstart: pos\n\t\t\tend:   pos\n\t\t}\n\t\tnew_text: text\n\t}\n}\n\npub fn (mut diff Diff) append_as_prev_line(line int, text string) {\n\tpos := Diff.line_begin_pos(line)\n\tdiff.edits << Edit{\n\t\trange:    lsp.Range{\n\t\t\tstart: pos\n\t\t\tend:   pos\n\t\t}\n\t\tnew_text: '${text}\\n'\n\t}\n}\n\npub fn (mut diff Diff) append_as_next_line(line int, text string) {\n\tpos := Diff.line_begin_pos(line)\n\tdiff.edits << Edit{\n\t\trange:    lsp.Range{\n\t\t\tstart: pos\n\t\t\tend:   pos\n\t\t}\n\t\tnew_text: '\\n${text}'\n\t}\n}\n\npub fn (mut diff Diff) to_workspace_edit() lsp.WorkspaceEdit {\n\treturn lsp.WorkspaceEdit{\n\t\tchanges: {\n\t\t\tdiff.uri: diff.edits.map(lsp.TextEdit{\n\t\t\t\trange:    it.range\n\t\t\t\tnew_text: it.new_text\n\t\t\t})\n\t\t}\n\t}\n}\n\nfn Diff.line_begin_pos(line int) lsp.Position {\n\treturn lsp.Position{\n\t\tline:      line\n\t\tcharacter: 0\n\t}\n}\n\nfn Diff.line_pos(line int, col int) lsp.Position {\n\treturn lsp.Position{\n\t\tline:      line\n\t\tcharacter: col\n\t}\n}\n"
  },
  {
    "path": "src/server/folding/visitor.v",
    "content": "module folding\n\nimport lsp\nimport analyzer.psi\n\npub struct FoldingVisitor {\n\tsource_text string\n\tlines       []string\nmut:\n\tranges                []lsp.FoldingRange\n\tlast_comment_end_line int = -2\n\tcomment_start_line    int = -1\n}\n\npub fn FoldingVisitor.new(file &psi.PsiFile) FoldingVisitor {\n\treturn FoldingVisitor{\n\t\tsource_text: file.source_text\n\t\tlines:       file.source_text.split_into_lines()\n\t}\n}\n\npub fn (mut v FoldingVisitor) accept(root psi.PsiElement) []lsp.FoldingRange {\n\tmut walker := psi.new_tree_walker(root.node())\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\tv.process_node(node)\n\t}\n\n\tv.flush_comment_group()\n\treturn v.ranges\n}\n\nfn (mut v FoldingVisitor) process_node(node psi.AstNode) {\n\tif node.type_name == .line_comment {\n\t\tv.process_line_comment(node)\n\t\treturn\n\t}\n\tv.flush_comment_group()\n\n\tmatch node.type_name {\n\t\t.block {\n\t\t\tv.fold_block(node)\n\t\t}\n\t\t.type_initializer {\n\t\t\tif body := node.child_by_field_name('body') {\n\t\t\t\tv.fold_block(body)\n\t\t\t}\n\t\t}\n\t\t.struct_declaration, .enum_declaration, .interface_declaration {\n\t\t\tv.fold_delimiters(node, '{', '}', lsp.folding_range_kind_region)\n\t\t}\n\t\t.global_var_declaration {\n\t\t\tv.fold_delimiters(node, '(', ')', lsp.folding_range_kind_region)\n\t\t}\n\t\t.import_list {\n\t\t\tv.fold_simple(node, lsp.folding_range_kind_imports)\n\t\t}\n\t\t.block_comment {\n\t\t\tv.fold_simple(node, lsp.folding_range_kind_comment)\n\t\t}\n\t\telse {}\n\t}\n}\n\nfn (mut v FoldingVisitor) fold_block(node psi.AstNode) {\n\tstart_line := int(node.start_point().row)\n\tend_line := int(node.end_point().row)\n\n\tif start_line < end_line {\n\t\tfinal_end_line := v.determine_end_line(end_line, '}')\n\t\tv.add_range(start_line, final_end_line, lsp.folding_range_kind_region)\n\t}\n}\n\nfn (mut v FoldingVisitor) fold_delimiters(node psi.AstNode, open string, close string, kind string) {\n\tcount := node.child_count()\n\tmut start_line := -1\n\tmut end_line := -1\n\n\tfor i in 0 .. count {\n\t\tchild := node.child(i) or { continue }\n\t\tif child.child_count() > 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\ttext := child.text(v.source_text)\n\t\tif text == open {\n\t\t\tstart_line = int(child.start_point().row)\n\t\t} else if text == close {\n\t\t\tend_line = int(child.start_point().row)\n\t\t}\n\t}\n\n\tif start_line != -1 && end_line > start_line {\n\t\tfinal_end_line := v.determine_end_line(end_line, close)\n\t\tv.add_range(start_line, final_end_line, kind)\n\t}\n}\n\nfn (mut v FoldingVisitor) fold_simple(node psi.AstNode, kind string) {\n\tstart_line := int(node.start_point().row)\n\tmut end_line := int(node.end_point().row)\n\n\tif node.end_point().column == 0 && end_line > start_line {\n\t\tend_line--\n\t}\n\n\tfor end_line > start_line && end_line < v.lines.len {\n\t\tif v.lines[end_line].trim_space() != '' {\n\t\t\tbreak\n\t\t}\n\t\tend_line--\n\t}\n\n\tif start_line < end_line {\n\t\tv.add_range(start_line, end_line, kind)\n\t}\n}\n\nfn (mut v FoldingVisitor) determine_end_line(end_line int, close string) int {\n\tif end_line >= v.lines.len {\n\t\treturn end_line\n\t}\n\n\tline := v.lines[end_line].trim_space()\n\tif line == close || line == close + ',' || line == close + ';' {\n\t\treturn end_line\n\t}\n\treturn end_line - 1\n}\n\n@[inline]\nfn (mut v FoldingVisitor) add_range(start int, end int, kind string) {\n\tv.ranges << lsp.FoldingRange{\n\t\tstart_line: start\n\t\tend_line:   end\n\t\tkind:       kind\n\t}\n}\n\nfn (mut v FoldingVisitor) process_line_comment(node psi.AstNode) {\n\tstart_line := int(node.start_point().row)\n\tend_line := int(node.end_point().row)\n\n\tif v.last_comment_end_line != -2 && start_line == v.last_comment_end_line + 1 {\n\t\tv.last_comment_end_line = end_line\n\t} else {\n\t\tv.flush_comment_group()\n\t\tv.comment_start_line = start_line\n\t\tv.last_comment_end_line = end_line\n\t}\n}\n\nfn (mut v FoldingVisitor) flush_comment_group() {\n\tstart := v.comment_start_line\n\tend := v.last_comment_end_line\n\n\tv.comment_start_line = -1\n\tv.last_comment_end_line = -2\n\n\tif start != -1 && end > start {\n\t\tv.add_range(start, end, lsp.folding_range_kind_comment)\n\t}\n}\n"
  },
  {
    "path": "src/server/general.v",
    "content": "module server\n\nimport lsp\nimport runtime\nimport os\nimport project\nimport metadata\nimport arrays\nimport config\nimport loglib\nimport analyzer.index\nimport server.protocol\nimport server.semantic\nimport server.progress\nimport server.intentions\nimport server.workspace\n\n// initialize sends the server capabilities to the client\npub fn (mut ls LanguageServer) initialize(params lsp.InitializeParams, mut wr ResponseWriter) lsp.InitializeResult {\n\tls.client_pid = params.process_id\n\tls.client = protocol.new_client(mut wr)\n\tls.progress = progress.new_tracker(mut ls.client)\n\tls.bg.start()\n\n\tls.root_uri = params.root_uri\n\tls.status = .initialized\n\tls.project_resolver = workspace.ProjectResolver.new(ls.root_uri.path())\n\n\tls.progress.support_work_done_progress = params.capabilities.window.work_done_progress\n\toptions := params.initialization_options\n\tif options is string {\n\t\tls.initialization_options = options.fields()\n\t}\n\n\tls.print_info(params.process_id, params.client_info)\n\tls.setup()\n\n\tls.register_intention(intentions.AddFlagAttributeIntention{})\n\tls.register_intention(intentions.AddHeapAttributeIntention{})\n\tls.register_intention(intentions.MakePublicIntention{})\n\n\tls.register_compiler_quick_fix(intentions.MakeMutableQuickFix{})\n\tls.register_compiler_quick_fix(intentions.ImportModuleQuickFix{})\n\n\treturn lsp.InitializeResult{\n\t\tcapabilities: lsp.ServerCapabilities{\n\t\t\ttext_document_sync:           lsp.TextDocumentSyncOptions{\n\t\t\t\topen_close: true\n\t\t\t\tchange:     .full\n\t\t\t\twill_save:  true\n\t\t\t\tsave:       lsp.SaveOptions{}\n\t\t\t}\n\t\t\thover_provider:               true\n\t\t\tdefinition_provider:          true\n\t\t\ttype_definition_provider:     true\n\t\t\treferences_provider:          lsp.ReferencesOptions{}\n\t\t\tdocument_formatting_provider: true\n\t\t\tcompletion_provider:          lsp.CompletionOptions{\n\t\t\t\tresolve_provider:   false\n\t\t\t\ttrigger_characters: ['.', ':', '(', '@']\n\t\t\t}\n\t\t\tsignature_help_provider:      lsp.SignatureHelpOptions{\n\t\t\t\ttrigger_characters:   ['(', ',']\n\t\t\t\tretrigger_characters: [',', ' ']\n\t\t\t}\n\t\t\tcode_lens_provider:           lsp.CodeLensOptions{}\n\t\t\tinlay_hint_provider:          lsp.InlayHintOptions{}\n\t\t\tsemantic_tokens_provider:     lsp.SemanticTokensOptions{\n\t\t\t\tlegend: lsp.SemanticTokensLegend{\n\t\t\t\t\ttoken_types:     semantic.semantic_types\n\t\t\t\t\ttoken_modifiers: semantic.semantic_modifiers\n\t\t\t\t}\n\t\t\t\trange:  true\n\t\t\t\tfull:   true\n\t\t\t}\n\t\t\trename_provider:              lsp.RenameOptions{\n\t\t\t\tprepare_provider: false\n\t\t\t}\n\t\t\tdocument_symbol_provider:     true\n\t\t\tworkspace_symbol_provider:    true\n\t\t\timplementation_provider:      true\n\t\t\tdocument_highlight_provider:  true\n\t\t\tcode_action_provider:         lsp.CodeActionOptions{\n\t\t\t\tcode_action_kinds: [lsp.quick_fix]\n\t\t\t}\n\t\t\tfolding_range_provider:       true\n\t\t\texecute_command_provider:     lsp.ExecuteCommandOptions{\n\t\t\t\tcommands: arrays.concat(ls.intentions.values().map(it.id),\n\t\t\t\t\t...ls.compiler_quick_fixes.values().map(it.id))\n\t\t\t}\n\t\t}\n\t\tserver_info:  lsp.ServerInfo{\n\t\t\tname:    metadata.manifest.name\n\t\t\tversion: metadata.manifest.version\n\t\t}\n\t}\n}\n\npub fn (mut ls LanguageServer) initialized(mut wr ResponseWriter) {\n\tloglib.info('-------- New session -------- ')\n\tls.indexing_mng.setup_empty_indexes()\n\n\tif ls.paths.vexe == '' || ls.paths.vlib_root == '' {\n\t\tls.client.send_server_status(health: 'error', quiescent: true)\n\t\treturn\n\t} else {\n\t\tls.client.send_server_status(health: 'ok')\n\t}\n\n\tmut work := ls.progress.start('Indexing:', 'roots...', '')\n\n\t// Used in tests to avoid indexing the standard library\n\tneed_index_stdlib := 'no-stdlib' !in ls.initialization_options\n\n\tif need_index_stdlib {\n\t\tls.indexing_mng.indexer.add_indexing_root(ls.paths.vmodules_root, .modules,\n\t\t\tls.paths.cache_dir)\n\t\tfor path in os.vmodules_paths()[1..] {\n\t\t\tif path.is_blank() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tls.indexing_mng.indexer.add_indexing_root(path, .modules, ls.paths.cache_dir)\n\t\t}\n\t\tls.indexing_mng.indexer.add_indexing_root(ls.paths.vlib_root, .standard_library,\n\t\t\tls.paths.cache_dir)\n\t}\n\n\tif stubs_root := ls.stubs_root() {\n\t\tls.indexing_mng.indexer.add_indexing_root(stubs_root, .stubs, ls.paths.cache_dir)\n\t}\n\n\tls.indexing_mng.indexer.add_indexing_root(ls.root_uri.path(), .workspace, ls.paths.cache_dir)\n\n\tstatus := ls.indexing_mng.indexer.index(fn [mut work, mut ls] (root index.IndexingRoot, i int) {\n\t\tpercentage := (i * 70) / ls.indexing_mng.indexer.count_roots()\n\t\twork.progress('${i}/${ls.indexing_mng.indexer.count_roots()} (${root.kind.readable_name()})',\n\t\t\tu32(percentage))\n\t\tls.client.log_message('Indexing ${root.root}', .info)\n\t})\n\n\twork.progress('Finish roots indexing', 70)\n\n\tif status == .needs_ensure_indexed {\n\t\twork.progress('Start ensure indexing', 71)\n\t\tls.indexing_mng.indexer.ensure_indexed()\n\t\twork.progress('Finish ensure indexing', 95)\n\t}\n\n\t// Used in tests to avoid indexing the standard library\n\tneed_save_index := 'no-index-save' !in ls.initialization_options\n\n\tls.indexing_mng.indexer.set_no_save(!need_save_index)\n\n\tls.indexing_mng.indexer.save_indexes() or {\n\t\tloglib.with_fields({\n\t\t\t'err': err.str()\n\t\t}).error('Failed to save index')\n\t}\n\n\tls.indexing_mng.setup_stub_indexes()\n\n\twork.end('Indexing finished')\n\n\tls.client.send_server_status(health: 'ok', quiescent: true)\n}\n\nfn (mut ls LanguageServer) setup() {\n\tls.setup_config_dir()\n\tls.setup_stubs()\n\n\tconfig_path := ls.find_config()\n\tif config_path == '' {\n\t\tls.client.log_message('No config found', .warning)\n\t\tloglib.warn('No config found')\n\t\tls.setup_toolchain()\n\t\tls.setup_vpaths()\n\t\treturn\n\t}\n\n\tconfig_content := os.read_file(config_path) or {\n\t\tls.client.log_message('Failed to read config: ${err}', .error)\n\n\t\tloglib.with_fields({\n\t\t\t'err': err.str()\n\t\t}).error('Failed to read config')\n\t\treturn\n\t}\n\n\tcfg := config.from_toml(ls.root_uri.path(), config_path, config_content) or {\n\t\tls.client.log_message('Failed to decode config: ${err}', .error)\n\t\tls.client.log_message('Using default config', .info)\n\n\t\tloglib.with_fields({\n\t\t\t'err': err.str()\n\t\t}).error('Failed to decode config')\n\t\tloglib.info('Using default config')\n\t\tconfig.EditorConfig{}\n\t}\n\n\tconfig_type := if cfg.is_local() { 'local' } else { 'global' }\n\tls.client.log_message('Using ${config_type} config: ${config_path}', .info)\n\n\tls.cfg = cfg\n\tif cfg.custom_vroot != '' {\n\t\tls.paths.vroot = os.expand_tilde_to_home(cfg.custom_vroot)\n\n\t\tls.client.log_message(\"Find custom VROOT path in '${cfg.path()}' config\", .info)\n\t\tls.client.log_message('Using \"${cfg.custom_vroot}\" as toolchain', .info)\n\n\t\tloglib.info(\"Find custom VROOT path in '${cfg.path()}' config\")\n\t\tloglib.info('Using \"${cfg.custom_vroot}\" as toolchain')\n\t}\n\n\tif cfg.custom_cache_dir != '' {\n\t\tls.paths.cache_dir = os.abs_path(os.expand_tilde_to_home(cfg.custom_cache_dir))\n\n\t\tif !os.exists(ls.paths.cache_dir) {\n\t\t\tos.mkdir_all(ls.paths.cache_dir) or {\n\t\t\t\tls.client.log_message('Failed to create custom analyzer caches directory: ${err}',\n\t\t\t\t\t.error)\n\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'err': err.str()\n\t\t\t\t}).error('Failed to create custom analyzer caches directory')\n\t\t\t}\n\t\t}\n\n\t\tls.client.log_message(\"Find custom cache dir path in '${cfg.path()}' config\", .info)\n\t\tls.client.log_message('Using \"${cfg.custom_cache_dir}\" as cache dir', .info)\n\n\t\tloglib.info(\"Find custom cache dir path in '${cfg.path()}' config\")\n\t\tloglib.info('Using \"${cfg.custom_cache_dir}\" as cache dir')\n\t}\n\n\tif ls.paths.vroot == '' {\n\t\t// if custom vroot is not set, try to find it\n\t\tls.setup_toolchain()\n\t}\n\n\tif ls.paths.cache_dir == '' {\n\t\tls.setup_cache_dir()\n\t}\n\n\tls.setup_vpaths()\n}\n\nfn (mut ls LanguageServer) setup_cache_dir() {\n\tif !os.exists(config.analyzer_caches_path) {\n\t\tos.mkdir_all(config.analyzer_caches_path) or {\n\t\t\tls.client.log_message('Failed to create analyzer caches directory: ${err}', .error)\n\n\t\t\tloglib.with_fields({\n\t\t\t\t'err': err.str()\n\t\t\t}).error('Failed to create analyzer caches directory')\n\t\t\treturn\n\t\t}\n\t}\n\n\t// if custom cache dir is not set, use default\n\tls.paths.cache_dir = config.analyzer_caches_path\n\n\tls.client.log_message('Using \"${ls.paths.cache_dir}\" as cache dir', .info)\n\tloglib.info('Using \"${ls.paths.cache_dir}\" as cache dir')\n}\n\nfn (mut ls LanguageServer) find_config() string {\n\troot := ls.root_uri.path()\n\tlocal_config_path := os.join_path(root, '.v-analyzer', 'config.toml')\n\tif os.exists(local_config_path) {\n\t\treturn local_config_path\n\t}\n\n\tglobal_config_path := os.join_path(config.analyzer_configs_path, 'config.toml')\n\tif os.exists(global_config_path) {\n\t\treturn global_config_path\n\t}\n\n\treturn ''\n}\n\nfn (mut ls LanguageServer) setup_toolchain() {\n\ttoolchain_candidates := project.get_toolchain_candidates()\n\tif toolchain_candidates.len == 0 {\n\t\tls.client.log_message(\"No toolchain candidates found, some of the features won't work properly.\nPlease, set `custom_vroot` in local or global config.\nGlobal config path: ${config.analyzer_configs_path}/${config.analyzer_config_name}\",\n\t\t\t.error)\n\t\tloglib.error(\"No toolchain candidates found, some of the features won't work properly.\nPlease, set `custom_vroot` in local or global config.\")\n\t\treturn\n\t}\n\n\tls.client.log_message('Found toolchain candidates:', .info)\n\tloglib.info('Found toolchain candidates:')\n\tfor toolchain_candidate in toolchain_candidates {\n\t\tls.client.log_message('  ${toolchain_candidate}', .info)\n\t\tloglib.info('  ${toolchain_candidate}')\n\t}\n\n\tls.client.log_message('Using \"${toolchain_candidates.first()}\" as toolchain', .info)\n\tloglib.info('Using \"${toolchain_candidates.first()}\" as toolchain')\n\tls.paths.vroot = toolchain_candidates.first()\n\n\tif toolchain_candidates.len > 1 {\n\t\tls.client.log_message('To set other toolchain, use `custom_vroot` in local or global config.\nGlobal config path: ${config.analyzer_configs_path}/${config.analyzer_config_name}',\n\t\t\t.info)\n\t}\n}\n\nfn (mut ls LanguageServer) setup_vpaths() {\n\t// Prior call of `ls.setup_toolchain()` ensures `ls.paths.vroot` is set.\n\tvexe_path := os.join_path(ls.paths.vroot, $if windows { 'v.exe' } $else { 'v' })\n\tif !os.is_file(vexe_path) {\n\t\tmsg := 'Failed to find V compiler!'\n\t\tls.client.log_message(msg, .error)\n\t\tloglib.error(msg)\n\t} else {\n\t\tls.paths.vexe = vexe_path\n\t\tls.reporter.compiler_path = vexe_path\n\t}\n\n\tvlib_path := os.join_path(ls.paths.vroot, 'vlib')\n\tif !os.is_dir(vlib_path) {\n\t\tmsg := 'Failed to find V standard library.'\n\t\tls.client.log_message(msg, .error)\n\t\tloglib.error(msg)\n\t} else {\n\t\tls.paths.vlib_root = vlib_path\n\t}\n\n\tvmodules_root := os.vmodules_dir()\n\tif !os.is_dir(vmodules_root) {\n\t\tmsg := 'Failed to find vmodules path.'\n\t\tls.client.log_message(msg, .error)\n\t\tloglib.error(msg)\n\t} else {\n\t\tls.paths.vmodules_root = vmodules_root\n\t\tmsg := 'Using \"${vmodules_root}\" as vmodules root.'\n\t\tls.client.log_message(msg, .info)\n\t\tloglib.info(msg)\n\t}\n}\n\nfn (mut ls LanguageServer) setup_config_dir() {\n\tif !os.exists(config.analyzer_configs_path) {\n\t\tos.mkdir_all(config.analyzer_configs_path) or {\n\t\t\tls.client.log_message('Failed to create analyzer configs directory: ${err}', .error)\n\n\t\t\tloglib.with_fields({\n\t\t\t\t'err': err.str()\n\t\t\t}).error('Failed to create analyzer configs directory')\n\t\t\treturn\n\t\t}\n\t}\n\n\tif !os.exists(config.analyzer_global_config_path) {\n\t\tls.client.log_message('Global config not found', .info)\n\t\tls.client.log_message('Creating default global analyzer config', .info)\n\n\t\tloglib.info('Global config not found')\n\t\tloglib.info('Creating default global analyzer config')\n\n\t\tos.write_file(config.analyzer_global_config_path, config.default) or {\n\t\t\tls.client.log_message('Failed to create global default analyzer config: ${err}', .error)\n\n\t\t\tloglib.with_fields({\n\t\t\t\t'err': err.str()\n\t\t\t}).error('Failed to create global default analyzer config')\n\t\t\treturn\n\t\t}\n\n\t\tls.client.log_message('Default analyzer config created at ${config.analyzer_global_config_path}',\n\t\t\t.info)\n\t\tloglib.info('Default analyzer config created at ${config.analyzer_global_config_path}')\n\t}\n}\n\nfn (mut ls LanguageServer) setup_stubs() {\n\tif os.exists(config.analyzer_stubs_path) {\n\t\tif os.exists(config.analyzer_stubs_version_path) {\n\t\t\tversion_string := os.read_file(config.analyzer_stubs_version_path) or {\n\t\t\t\tls.client.log_message('Failed to read stubs version: ${err}', .error)\n\n\t\t\t\tloglib.with_fields({\n\t\t\t\t\t'err': err.str()\n\t\t\t\t}).error('Failed to read stubs version')\n\t\t\t\t'0'\n\t\t\t}\n\t\t\tversion := version_string.int()\n\n\t\t\tif version == ls.stubs_version {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tls.client.log_message('Stubs version mismatch, unpacking new stubs', .info)\n\t\tloglib.info('Stubs version mismatch, unpacking new stubs')\n\n\t\tos.rmdir_all(config.analyzer_stubs_path) or {\n\t\t\tls.client.log_message('Failed to remove old stubs: ${err}', .error)\n\n\t\t\tloglib.with_fields({\n\t\t\t\t'err': err.str()\n\t\t\t}).error('Failed to remove old stubs')\n\t\t}\n\t}\n\n\tstubs := metadata.embed_fs()\n\tstubs.unpack_to(config.analyzer_stubs_path) or {\n\t\tls.client.log_message('Failed to unpack stubs: ${err}', .error)\n\n\t\tloglib.with_fields({\n\t\t\t'err': err.str()\n\t\t}).error('Failed to unpack stubs')\n\t}\n\n\tos.write_file(config.analyzer_stubs_version_path, ls.stubs_version.str()) or {\n\t\tls.client.log_message('Failed to write stubs version: ${err}', .error)\n\n\t\tloglib.with_fields({\n\t\t\t'err': err.str()\n\t\t}).error('Failed to write stubs version')\n\t}\n}\n\n// shutdown sets the state to shutdown but does not exit\n@[noreturn]\npub fn (mut ls LanguageServer) shutdown() {\n\tls.bg.stop()\n\tls.status = .shutdown\n\tls.main_parser.free()\n\tls.exit()\n}\n\n// exit stops the process\n@[noreturn]\npub fn (mut ls LanguageServer) exit() {\n\t// move exit to shutdown for now\n\t// == .shutdown => 0\n\t// != .shutdown => 1\n\tecode := int(ls.status != .shutdown)\n\tloglib.info('v-analyzer exiting with ${ls.status}, exit code: ${ecode}')\n\texit(ecode)\n}\n\nfn (mut ls LanguageServer) print_info(process_id int, client_info lsp.ClientInfo) {\n\tarch := if runtime.is_64bit() { 64 } else { 32 }\n\tclient_name := if client_info.name.len != 0 {\n\t\t'${client_info.name} ${client_info.version}'\n\t} else {\n\t\t'Unknown'\n\t}\n\tls.client.log_message('v-analyzer version: ${metadata.manifest.version}, commit: ${metadata.build_commit}, OS: ${os.user_os()} x${arch}',\n\t\t.info)\n\tls.client.log_message('v-analyzer executable path: ${os.executable()}', .info)\n\tls.client.log_message('v-analyzer build with V ${@VHASH}', .info)\n\tls.client.log_message('v-analyzer build at ${metadata.build_datetime}', .info)\n\tls.client.log_message('Client / Editor: ${client_name} (PID: ${process_id})', .info)\n\n\tloglib.with_fields({\n\t\t'client_name':  client_name\n\t\t'process_id':   process_id.str()\n\t\t'os':           os.user_os()\n\t\t'arch':         'x${arch}'\n\t\t'executable':   os.executable()\n\t\t'build_with':   @VHASH\n\t\t'build_at':     metadata.build_datetime\n\t\t'build_commit': metadata.build_commit\n\t}).info('v-analyzer started')\n}\n"
  },
  {
    "path": "src/server/hints/InlayHintsVisitor.v",
    "content": "module hints\n\nimport lsp\nimport config\nimport analyzer.psi\nimport analyzer.psi.types\n\npub struct InlayHintsVisitor {\npub:\n\tcfg config.InlayHintsConfig\npub mut:\n\tlines  int\n\tresult []lsp.InlayHint = []lsp.InlayHint{cap: 1000}\n}\n\npub fn (mut v InlayHintsVisitor) accept(root psi.PsiElement) {\n\tfile := root.containing_file() or { return }\n\tv.lines = file.source_text.count('\\n')\n\n\tmut walker := psi.new_tree_walker(root.node())\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\tv.process_node(node, file)\n\t}\n}\n\npub fn (mut v InlayHintsVisitor) process_node(node psi.AstNode, containing_file &psi.PsiFile) {\n\tif node.type_name == .range && v.cfg.enable_range_hints {\n\t\toperator := node.child_by_field_name('operator') or { return }\n\t\tstart_point := operator.start_point()\n\t\tend_point := operator.end_point()\n\n\t\tneed_left := if _ := node.child_by_field_name('start') { true } else { false }\n\t\tneed_right := if _ := node.child_by_field_name('end') { true } else { false }\n\n\t\tif need_left {\n\t\t\tv.result << lsp.InlayHint{\n\t\t\t\tposition: lsp.Position{\n\t\t\t\t\tline:      int(start_point.row)\n\t\t\t\t\tcharacter: int(start_point.column)\n\t\t\t\t}\n\t\t\t\tlabel:    '≤'\n\t\t\t\tkind:     .type_\n\t\t\t}\n\t\t}\n\t\tif need_right {\n\t\t\tv.result << lsp.InlayHint{\n\t\t\t\tposition: lsp.Position{\n\t\t\t\t\tline:      int(end_point.row)\n\t\t\t\t\tcharacter: int(end_point.column)\n\t\t\t\t}\n\t\t\t\tlabel:    '<'\n\t\t\t\tkind:     .type_\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\n\tif node.type_name == .const_definition && v.cfg.enable_constant_type_hints {\n\t\telement := psi.create_element(node, containing_file)\n\t\tif element is psi.ConstantDefinition {\n\t\t\tif element.name() == '_' {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trange := element.identifier_text_range()\n\n\t\t\tv.result << lsp.InlayHint{\n\t\t\t\tposition: lsp.Position{\n\t\t\t\t\tline:      range.line\n\t\t\t\t\tcharacter: range.end_column\n\t\t\t\t}\n\t\t\t\tlabel:    ': ' + element.get_type().readable_name()\n\t\t\t\tkind:     .type_\n\t\t\t}\n\t\t}\n\t}\n\n\tif v.cfg.enable_type_hints {\n\t\tdef := psi.node_to_var_definition(node, containing_file, none)\n\t\tif !isnil(def) && def.name() != '_' {\n\t\t\ttyp := def.get_type()\n\t\t\trange := def.text_range()\n\n\t\t\tv.result << lsp.InlayHint{\n\t\t\t\tposition: lsp.Position{\n\t\t\t\t\tline:      range.line\n\t\t\t\t\tcharacter: range.end_column\n\t\t\t\t}\n\t\t\t\tlabel:    ': ' + typ.readable_name()\n\t\t\t\tkind:     .type_\n\t\t\t}\n\t\t}\n\t}\n\n\tif node.type_name == .or_block_expression && v.cfg.enable_implicit_err_hints {\n\t\texpression_node := node.first_child() or { return }\n\t\texpression := psi.create_element(expression_node, containing_file)\n\t\ttyp := psi.infer_type(expression)\n\t\tif typ !is types.ResultType {\n\t\t\t// show `err ->` hint only for `Result` type\n\t\t\treturn\n\t\t}\n\n\t\tor_block := node.last_child() or { return }\n\t\tblock := or_block.child_by_field_name('block') or { return }\n\t\tv.handle_implicit_error_variable(block)\n\t}\n\n\tif node.type_name == .else_branch && v.cfg.enable_implicit_err_hints {\n\t\tv.handle_if_unwrapping(node, containing_file)\n\t}\n\n\tif node.type_name == .call_expression && v.cfg.enable_parameter_name_hints {\n\t\tv.handle_call_expression(node, containing_file)\n\t}\n\n\tif node.type_name == .enum_field_definition && v.cfg.enable_enum_field_value_hints {\n\t\tv.handle_enum_field(node, containing_file)\n\t}\n}\n\npub fn (mut v InlayHintsVisitor) handle_enum_field(enum_field psi.AstNode, containing_file &psi.PsiFile) {\n\telement := psi.create_element(enum_field, containing_file)\n\tif element is psi.EnumFieldDeclaration {\n\t\tif _ := element.value() {\n\t\t\t// don't show hint for enum fields with explicit values\n\t\t\treturn\n\t\t}\n\n\t\tvalue_presentation := element.value_presentation(true)\n\n\t\ttext_range := element.text_range()\n\t\tv.result << lsp.InlayHint{\n\t\t\tposition: lsp.Position{\n\t\t\t\tline:      int(text_range.line)\n\t\t\t\tcharacter: int(text_range.end_column)\n\t\t\t}\n\t\t\tlabel:    ' = ${value_presentation}'\n\t\t\tkind:     .type_\n\t\t}\n\t}\n}\n\npub fn (mut v InlayHintsVisitor) handle_call_expression(call psi.AstNode, containing_file &psi.PsiFile) {\n\tif v.lines > 1000 {\n\t\t// don't show this hints for large files\n\t\treturn\n\t}\n\n\tcall_expression := psi.create_element(call, containing_file)\n\tif call_expression is psi.CallExpression {\n\t\targuments := call_expression.arguments()\n\t\tcalled := call_expression.resolve() or { return }\n\t\tif called is psi.SignatureOwner {\n\t\t\tsignature := called.signature() or { return }\n\t\t\tfor i, param in signature.parameters() {\n\t\t\t\tname := if param is psi.ParameterDeclaration { param.name() } else { '_' }\n\t\t\t\tif name == '_' {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\targ := arguments[i] or { continue }\n\t\t\t\tif arg.node().type_name == .keyed_element {\n\t\t\t\t\t// don't show hint for named arguments\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\targ_inner := if arg.node().type_name == .mutable_expression {\n\t\t\t\t\targ.last_child() or { continue }\n\t\t\t\t} else {\n\t\t\t\t\targ\n\t\t\t\t}\n\t\t\t\tif arg_inner.text_matches(name) {\n\t\t\t\t\t// don't show hint if argument name matches parameter name\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\targ_range := arg.text_range()\n\t\t\t\tv.result << lsp.InlayHint{\n\t\t\t\t\tposition: lsp.Position{\n\t\t\t\t\t\tline:      arg_range.line\n\t\t\t\t\t\tcharacter: arg_range.column\n\t\t\t\t\t}\n\t\t\t\t\tlabel:    '${name}: '\n\t\t\t\t\tkind:     .parameter\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\npub fn (mut v InlayHintsVisitor) handle_if_unwrapping(node psi.AstNode, containing_file &psi.PsiFile) {\n\tparent_if_expression := node.parent_of_type(.if_expression) or { return }\n\n\tguard := parent_if_expression.child_by_field_name('guard') or { return }\n\texpression_list := guard.child_by_field_name('expression_list') or { return }\n\texpression := expression_list.first_child() or { return }\n\texpr_type := psi.infer_type(psi.create_element(expression, containing_file))\n\n\tif expr_type !is types.ResultType {\n\t\t// show `err ->` hint only for `Result` type\n\t\treturn\n\t}\n\n\tblock := node.child_by_field_name('block') or { return }\n\tv.handle_implicit_error_variable(block)\n}\n\npub fn (mut v InlayHintsVisitor) handle_implicit_error_variable(block psi.AstNode) {\n\tstart_point := block.start_point()\n\tend_point := block.end_point()\n\n\tif start_point.row == end_point.row {\n\t\t// don't show hint if 'or { ... }'\n\t\treturn\n\t}\n\n\tv.result << lsp.InlayHint{\n\t\tposition: lsp.Position{\n\t\t\tline:      int(start_point.row)\n\t\t\tcharacter: int(start_point.column + 1)\n\t\t}\n\t\tlabel:    ' err →'\n\t\tkind:     .parameter\n\t}\n}\n"
  },
  {
    "path": "src/server/inspections/Report.v",
    "content": "module inspections\n\nimport analyzer.psi\n\npub enum ReportKind {\n\terror\n\twarning\n\tnotice\n}\n\npub struct Report {\npub:\n\tkind     ReportKind\n\tcode     string\n\tmessage  string\n\tfilepath string\n\tsource   string\n\trange    psi.TextRange\n}\n"
  },
  {
    "path": "src/server/inspections/ReportsSource.v",
    "content": "module inspections\n\nimport lsp\n\npub interface ReportsSource {\nmut:\n\tprocess(uri lsp.DocumentUri) []Report\n}\n"
  },
  {
    "path": "src/server/inspections/compiler/CompilerReportsSource.v",
    "content": "module compiler\n\nimport lsp\nimport server.inspections\n\npub struct CompilerReportsSource {\npub:\n\tcompiler_path string\n}\n\npub fn (mut c CompilerReportsSource) process(uri lsp.DocumentUri, project_root string) []inspections.Report {\n\treports := exec_compiler_diagnostics(c.compiler_path, uri, project_root) or { return [] }\n\treturn reports\n}\n"
  },
  {
    "path": "src/server/inspections/compiler/utils.v",
    "content": "module compiler\n\nimport os\nimport lsp\nimport term\nimport server.inspections\nimport analyzer.psi\n\nfn parse_compiler_diagnostic(msg string) ?inspections.Report {\n\tlines := msg.split_into_lines()\n\tif lines.len == 0 {\n\t\treturn none\n\t}\n\n\tmut err_underline := ''\n\tfor line in lines {\n\t\tif line.contains('~') {\n\t\t\terr_underline = line\n\t\t\tbreak\n\t\t}\n\t}\n\tunderline_width := err_underline.count('~')\n\n\tfirst_line := lines.first()\n\n\tline_colon_idx :=\n\t\tfirst_line.index_after(':', 2) or { return none } // deal with `d:/v/...:2:4: error: ...`\n\tmut filepath := first_line[..line_colon_idx]\n\t$if windows {\n\t\tfilepath = filepath.replace('/', '\\\\')\n\t}\n\tcol_colon_idx := first_line.index_after(':', line_colon_idx + 1) or { return none }\n\tcolon_sep_idx := first_line.index_after(':', col_colon_idx + 1) or { return none }\n\tmsg_type_colon_idx := first_line.index_after(':', colon_sep_idx + 1) or { return none }\n\n\tline_nr := first_line[line_colon_idx + 1..col_colon_idx].int() - 1\n\tcol_nr := first_line[col_colon_idx + 1..colon_sep_idx].int() - 1\n\tmsg_type := first_line[colon_sep_idx + 1..msg_type_colon_idx].trim_space()\n\tmsg_content := first_line[msg_type_colon_idx + 1..].trim_space()\n\n\tdiag_kind := match msg_type {\n\t\t'error' { inspections.ReportKind.error }\n\t\t'warning' { inspections.ReportKind.warning }\n\t\t//'notice' { inspections.ReportKind.notice }\n\t\telse { inspections.ReportKind.notice }\n\t}\n\n\treturn inspections.Report{\n\t\trange:    psi.TextRange{\n\t\t\tline:       line_nr\n\t\t\tcolumn:     col_nr\n\t\t\tend_line:   line_nr\n\t\t\tend_column: col_nr + underline_width\n\t\t}\n\t\tkind:     diag_kind\n\t\tmessage:  msg_content\n\t\tfilepath: filepath\n\t}\n}\n\nfn exec_compiler_diagnostics(compiler_path string, uri lsp.DocumentUri, project_root string) ?[]inspections.Report {\n\tfilepath := uri.path()\n\tis_script := filepath.ends_with('.vsh') || filepath.ends_with('.vv')\n\n\tcheck_target := if is_script { filepath } else { project_root }\n\tres := os.execute('${compiler_path} -enable-globals -shared -check ${check_target}')\n\n\tif res.exit_code == 0 {\n\t\treturn none\n\t}\n\n\toutput_lines := res.output.split_into_lines().map(term.strip_ansi(it))\n\terrors := split_lines_to_errors(output_lines)\n\n\tcurrent_file_abs := os.real_path(filepath)\n\tmut reports := []inspections.Report{}\n\n\tfor error in errors {\n\t\treport := parse_compiler_diagnostic(error) or { continue }\n\n\t\t// ignore this error\n\t\tif report.message.contains('unexpected eof') {\n\t\t\tcontinue\n\t\t}\n\n\t\treport_file_abs := os.real_path(report.filepath)\n\t\tif os.to_slash(report_file_abs) != os.to_slash(current_file_abs) {\n\t\t\tcontinue\n\t\t}\n\n\t\treports << inspections.Report{\n\t\t\t...report\n\t\t\tfilepath: filepath\n\t\t}\n\t}\n\treturn reports\n}\n\nfn split_lines_to_errors(lines []string) []string {\n\tmut result := []string{}\n\tmut last_error := ''\n\n\tfor _, line in lines {\n\t\tif line.starts_with(' ') {\n\t\t\t// additional context of an error\n\t\t\tlast_error += '\\n' + line\n\t\t} else {\n\t\t\tif last_error.len > 0 {\n\t\t\t\tresult << last_error\n\t\t\t}\n\t\t\tlast_error = line\n\t\t}\n\t}\n\n\tif last_error.len > 0 {\n\t\tresult << last_error\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "src/server/intentions/AddFlagAttributeIntention.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\nimport server.tform\nimport server.file_diff\n\npub struct AddFlagAttributeIntention {\n\tid   string = 'v-analyzer.add_flag_attribute'\n\tname string = 'Add [flag] attribute'\n}\n\nfn (_ &AddFlagAttributeIntention) is_available(ctx IntentionContext) bool {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos) or { return false }\n\n\tif declaration is psi.EnumDeclaration {\n\t\treturn !declaration.is_flag()\n\t}\n\n\treturn false\n}\n\nfn (_ &AddFlagAttributeIntention) invoke(ctx IntentionContext) ?lsp.WorkspaceEdit {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos) or { return none }\n\tstart_line := declaration.identifier_text_range().line\n\turi := ctx.containing_file.uri()\n\n\tmut diff := file_diff.Diff.for_file(uri)\n\tdiff.append_as_prev_line(start_line, '[flag]')\n\treturn diff.to_workspace_edit()\n}\n"
  },
  {
    "path": "src/server/intentions/AddHeapAttributeIntention.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\nimport server.tform\nimport server.file_diff\n\npub struct AddHeapAttributeIntention {\n\tid   string = 'v-analyzer.add_heap_attribute'\n\tname string = 'Add [heap] attribute'\n}\n\nfn (_ &AddHeapAttributeIntention) is_available(ctx IntentionContext) bool {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos) or { return false }\n\n\tif declaration is psi.StructDeclaration {\n\t\treturn !declaration.is_heap()\n\t}\n\n\treturn false\n}\n\nfn (_ &AddHeapAttributeIntention) invoke(ctx IntentionContext) ?lsp.WorkspaceEdit {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos) or { return none }\n\tstart_line := declaration.identifier_text_range().line\n\turi := ctx.containing_file.uri()\n\n\tmut diff := file_diff.Diff.for_file(uri)\n\tdiff.append_as_prev_line(start_line, '[heap]')\n\treturn diff.to_workspace_edit()\n}\n"
  },
  {
    "path": "src/server/intentions/CompilerQuickFix.v",
    "content": "module intentions\n\npub interface CompilerQuickFix {\n\tIntention\n\tis_matched_message(msg string) bool\n}\n"
  },
  {
    "path": "src/server/intentions/ImportModuleQuickFix.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\nimport server.tform\nimport server.file_diff\n\npub struct ImportModuleQuickFix {\n\tid   string = 'v-analyzer.import_module'\n\tname string = 'Import module'\n}\n\nfn (_ &ImportModuleQuickFix) is_matched_message(msg string) bool {\n\treturn msg.contains('undefined ident')\n}\n\nfn (_ &ImportModuleQuickFix) is_available(ctx IntentionContext) bool {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\telement := ctx.containing_file.find_element_at_pos(pos) or { return false }\n\treference_expression := element.parent_of_type(.reference_expression) or { return false }\n\tif reference_expression is psi.ReferenceExpression {\n\t\tif _ := reference_expression.qualifier() {\n\t\t\treturn false\n\t\t}\n\n\t\tmodule_name := reference_expression.get_text()\n\t\tmodules := stubs_index.get_modules_by_name(module_name)\n\t\tif modules.len == 0 {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\treturn false\n}\n\nfn (_ &ImportModuleQuickFix) invoke(ctx IntentionContext) ?lsp.WorkspaceEdit {\n\turi := ctx.containing_file.uri()\n\tpos := tform.lsp_position_to_position(ctx.position)\n\telement := ctx.containing_file.find_element_at_pos(pos)?\n\treference_expression := element.parent_of_type(.reference_expression)?\n\n\tmodule_name := reference_expression.get_text()\n\tmodules := stubs_index.get_modules_by_name(module_name)\n\tif modules.len == 0 {\n\t\treturn none\n\t}\n\n\tmod := modules.first()\n\tfile := mod.containing_file() or { return none }\n\tmodule_fqn := file.module_fqn()\n\n\timports := ctx.containing_file.get_imports()\n\n\tmut extra_newline := ''\n\tmut line_to_insert := 0\n\tif imports.len > 0 {\n\t\tline_to_insert = imports.last().text_range().line + 1\n\t} else if mod_clause := ctx.containing_file.module_clause() {\n\t\tline_to_insert = mod_clause.text_range().line + 2\n\t\textra_newline = '\\n'\n\t} else {\n\t\textra_newline = '\\n'\n\t\tline_to_insert = 0\n\t}\n\n\tmut diff := file_diff.Diff.for_file(uri)\n\tdiff.append_as_prev_line(line_to_insert, 'import ' + module_fqn + extra_newline)\n\treturn diff.to_workspace_edit()\n}\n"
  },
  {
    "path": "src/server/intentions/Intention.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\n\npub struct IntentionContext {\n\t// file where this intention is available.\n\tcontaining_file &psi.PsiFile\n\t// position where this intention is available.\n\tposition lsp.Position\n}\n\npub fn IntentionContext.from(containing_file &psi.PsiFile, position lsp.Position) IntentionContext {\n\treturn IntentionContext{\n\t\tcontaining_file: containing_file\n\t\tposition:        position\n\t}\n}\n\n// Intention actions are invoked by pressing Alt-Enter in the code\n// editor at the location where an intention is available.\npub interface Intention {\n\t// unique id of the intention.\n\t// This id is equivalent to the id of the command that is\n\t// invoked when user selects this intention.\n\tid   string\n\tname string // name to be shown in the list of available actions, if this action is available.\n\t// is_available checks whether this intention is available at a caret offset in the file.\n\t// If this method returns true, a light bulb for this intention is shown.\n\tis_available(ctx IntentionContext) bool\n\t// invoke called when user invokes intention. This method is called inside command.\n\tinvoke(ctx IntentionContext) ?lsp.WorkspaceEdit\n}\n"
  },
  {
    "path": "src/server/intentions/MakeMutableQuickFix.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\nimport server.file_diff\nimport server.tform\n\npub struct MakeMutableQuickFix {\n\tid   string = 'v-analyzer.make_mutable'\n\tname string = 'Make mutable'\n}\n\nfn (_ &MakeMutableQuickFix) is_matched_message(msg string) bool {\n\treturn msg.contains('is immutable')\n}\n\nfn (_ &MakeMutableQuickFix) is_available(_ IntentionContext) bool {\n\treturn true\n}\n\nfn (_ &MakeMutableQuickFix) invoke(ctx IntentionContext) ?lsp.WorkspaceEdit {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\tref := find_reference_at_pos(ctx.containing_file, pos)?\n\turi := ctx.containing_file.uri()\n\n\tmut diff := file_diff.Diff.for_file(uri)\n\n\tresolved := ref.resolve()?\n\ttext_range := resolved.text_range()\n\tif resolved is psi.MutabilityOwner {\n\t\tif resolved.is_mutable() {\n\t\t\treturn none\n\t\t}\n\n\t\tmut column := text_range.column\n\n\t\tif resolved is psi.Receiver {\n\t\t\tcolumn += 1\n\t\t}\n\n\t\tdiff.append_to(text_range.line, column, 'mut ')\n\t}\n\n\treturn diff.to_workspace_edit()\n}\n"
  },
  {
    "path": "src/server/intentions/MakePublicIntention.v",
    "content": "module intentions\n\nimport lsp\nimport analyzer.psi\nimport server.tform\nimport server.file_diff\n\npub struct MakePublicIntention {\n\tid   string = 'v-analyzer.make_public'\n\tname string = 'Make public'\n}\n\nfn (_ &MakePublicIntention) is_available(ctx IntentionContext) bool {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos) or { return false }\n\treturn !declaration.is_public()\n}\n\nfn (_ &MakePublicIntention) invoke(ctx IntentionContext) ?lsp.WorkspaceEdit {\n\tpos := tform.lsp_position_to_position(ctx.position)\n\tdeclaration := find_declaration_at_pos(ctx.containing_file, pos)?\n\n\turi := ctx.containing_file.uri()\n\n\tmut start_line := declaration.identifier_text_range().line\n\tif declaration is psi.ConstantDefinition {\n\t\tdecl := declaration.parent()?\n\t\tif decl is psi.ConstantDeclaration {\n\t\t\tstart_line = decl.text_range().line\n\t\t}\n\t}\n\n\tmut diff := file_diff.Diff.for_file(uri)\n\tdiff.append_to_begin(start_line, 'pub ')\n\treturn diff.to_workspace_edit()\n}\n"
  },
  {
    "path": "src/server/intentions/utils.v",
    "content": "module intentions\n\nimport analyzer.psi\n\nfn find_declaration_at_pos(file &psi.PsiFile, pos psi.Position) ?psi.PsiNamedElement {\n\telement := file.find_element_at_pos(pos) or { return none }\n\tif element !is psi.Identifier {\n\t\treturn none\n\t}\n\n\tparent := element.parent() or { return none }\n\tif parent is psi.PsiNamedElement {\n\t\treturn parent\n\t}\n\n\tif parent.node().type_name == .overridable_operator {\n\t\tgrand := parent.parent() or { return none }\n\t\tif grand is psi.PsiNamedElement {\n\t\t\treturn grand\n\t\t}\n\t}\n\n\treturn none\n}\n\nfn find_reference_at_pos(file &psi.PsiFile, pos psi.Position) ?&psi.ReferenceExpression {\n\telement := file.find_element_at_pos(pos) or { return none }\n\tparent := element.parent() or { return none }\n\tif parent is psi.ReferenceExpression {\n\t\treturn parent\n\t}\n\n\treturn none\n}\n"
  },
  {
    "path": "src/server/language_server.v",
    "content": "module server\n\nimport json\nimport jsonrpc\nimport lsp\nimport time\nimport analyzer\nimport analyzer.parser\nimport os\nimport config\nimport loglib\nimport server.progress\nimport server.protocol\nimport server.intentions\nimport server.workspace\n\npub enum ServerStatus {\n\toff\n\tinitialized\n\tshutdown\n}\n\npub struct LanguageServer {\npub mut:\n\t// status is the current status of the server.\n\tstatus ServerStatus = .off\n\t// root_uri is the URI of the workspace root.\n\troot_uri lsp.DocumentUri\n\t// client is a wrapper over `jsonrpc.ResponseWriter` that\n\t// can be used to send notifications and responses to the client.\n\tclient &protocol.Client = unsafe { nil }\n\t// client_pid is the process ID of this server.\n\tclient_pid int\n\twriter     &ResponseWriter = unsafe { nil }\n\t// opened_files describes all open files in the editor.\n\t//\n\t// When a file is opened, the `did_open` method is called,\n\t// which adds the file to `opened_files`.\n\t//\n\t// When the file is closed, the `did_close` method is called,\n\t// which removes the file from `opened_files`.\n\topened_files map[lsp.DocumentUri]analyzer.OpenedFile\n\tpaths        struct {\n\tmut:\n\t\t// vmodules_root is the path to the vmodules directory.\n\t\tvmodules_root string\n\t\t// vroot is the path to the directory of the V compiler.\n\t\tvroot string\n\t\t// vexe is the path to the V compiler.\n\t\tvexe string\n\t\t// vlib_root is the path to the directory of the V standard library.\n\t\tvlib_root string\n\t\t// cache_dir is the path to the directory with the cache.\n\t\tcache_dir string\n\t}\n\t// stubs_version incremented on each change in stubs\n\t//\n\t// See also `LanguageServer.setup_stubs()`\n\tstubs_version int = 4\n\t// initialization_options is a list of custom initialization options.\n\t// Used to pass custom options in tests.\n\tinitialization_options []string\n\t// cfg describes the editor configuration from `config.toml`.\n\tcfg config.EditorConfig\n\t// bg is a background thread that is designed to perform long-running operations,\n\t// such as file analyze with third-party tools.\n\tbg BackgroundThread\n\t// reporter is used to report diagnostics to the client.\n\treporter &DiagnosticReporter = &DiagnosticReporter{}\n\t// intentions is a map of all intentions that are available in the editor.\n\t// Use `LanguageServer.register_intention()` to register a new intention.\n\tintentions map[string]intentions.Intention\n\t// compiler_quick_fixes is a map of all quick fixes for compiler errors\n\t// that are available in the editor.\n\t// Use `LanguageServer.register_compiler_quick_fix()` to register a new quick fix.\n\tcompiler_quick_fixes map[string]intentions.CompilerQuickFix\n\t// progress is used to report progress to the client.\n\t// For now it is used only to report progress of indexing.\n\tprogress &progress.Tracker = unsafe { nil }\n\t// indexing_mng is used to manage indexing.\n\tindexing_mng analyzer.IndexingManager\n\t// project_resolver is used to resolve the project root for a given file.\n\tproject_resolver &workspace.ProjectResolver = unsafe { nil }\n\t// main_parser is the parser used only in main thread for handling didChange requests.\n\tmain_parser &parser.Parser = parser.Parser.new()\n}\n\npub fn LanguageServer.new(indexing analyzer.IndexingManager) &LanguageServer {\n\treturn &LanguageServer{\n\t\tindexing_mng: indexing\n\t\twriter:       unsafe { nil } // will be initialized in `initialize`\n\t\tclient:       unsafe { nil } // will be initialized in `initialize`\n\t\tprogress:     unsafe { nil } // will be initialized in `initialize`\n\t}\n}\n\npub fn (mut _ LanguageServer) stubs_root() ?string {\n\tif !os.exists(config.analyzer_stubs_path) {\n\t\treturn none\n\t}\n\treturn config.analyzer_stubs_path\n}\n\npub fn (mut ls LanguageServer) get_file(uri lsp.DocumentUri) ?analyzer.OpenedFile {\n\treturn ls.opened_files[uri] or {\n\t\tloglib.with_fields({\n\t\t\t'uri': uri.str()\n\t\t}).warn('Cannot find file in opened_files')\n\t\treturn none\n\t}\n}\n\npub fn (mut ls LanguageServer) handle_jsonrpc(request &jsonrpc.Request, mut rw jsonrpc.ResponseWriter) ! {\n\t// initialize writer upon receiving the first request\n\tif isnil(ls.writer) {\n\t\tls.writer = rw.server.writer(own_buffer: true)\n\t}\n\n\twatch := time.new_stopwatch(auto_start: true)\n\n\tmut w := unsafe { &ResponseWriter(rw) }\n\n\t// The server will log a send request/notification\n\t// log based on the the received payload since the spec\n\t// doesn't indicate a way to log on the client side and\n\t// notify it to the server.\n\t//\n\t// Notification has no ID attached so the server can detect\n\t// if its a notification or a request payload by checking\n\t// if the ID is empty.\n\tmatch request.method {\n\t\t// Note: LSP specification is unclear whether or not\n\t\t// a shutdown request is allowed before server init\n\t\t// but we'll just put it here since we want to formally\n\t\t// shutdown the server after a certain timeout period.\n\t\t'shutdown' {\n\t\t\tls.shutdown()\n\t\t\treturn\n\t\t}\n\t\t'exit' {\n\t\t\tls.exit()\n\t\t\treturn\n\t\t}\n\t\telse {}\n\t}\n\n\tif ls.status != .initialized {\n\t\tif request.method == 'initialize' {\n\t\t\tparams := json.decode(lsp.InitializeParams, request.params) or { return err }\n\t\t\tw.write(ls.initialize(params, mut rw))\n\t\t} else if ls.status == .shutdown {\n\t\t\treturn jsonrpc.invalid_request\n\t\t} else {\n\t\t\treturn jsonrpc.server_not_initialized\n\t\t}\n\n\t\tloglib.with_fields({\n\t\t\t'method':   request.method\n\t\t\t'duration': watch.elapsed().str()\n\t\t}).log_one(.info, 'Request finished')\n\t\treturn\n\t}\n\tmatch request.method {\n\t\t// not only requests but also notifications\n\t\t'initialized' {\n\t\t\tls.initialized(mut rw)\n\t\t}\n\t\t'textDocument/didOpen' {\n\t\t\tparams := json.decode(lsp.DidOpenTextDocumentParams, request.params) or { return err }\n\t\t\tls.did_open(params)\n\t\t}\n\t\t'textDocument/didSave' {\n\t\t\tparams := json.decode(lsp.DidSaveTextDocumentParams, request.params) or { return err }\n\t\t\tls.did_save(params)\n\t\t}\n\t\t'textDocument/didChange' {\n\t\t\tparams := json.decode(lsp.DidChangeTextDocumentParams, request.params) or { return err }\n\t\t\tls.did_change(params)\n\t\t}\n\t\t'textDocument/didClose' {\n\t\t\tparams := json.decode(lsp.DidCloseTextDocumentParams, request.params) or { return err }\n\t\t\tls.did_close(params)\n\t\t}\n\t\t'textDocument/willSave' {\n\t\t\t// params := json.decode(lsp.WillSaveTextDocumentParams, request.params) or {\n\t\t\t// \treturn err\n\t\t\t// }\n\t\t\t// ls.will_save(params)\n\t\t}\n\t\t'textDocument/formatting' {\n\t\t\tparams := json.decode(lsp.DocumentFormattingParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.formatting(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/documentSymbol' {\n\t\t\tparams := json.decode(lsp.DocumentSymbolParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.document_symbol(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'workspace/symbol' {\n\t\t\tparams := json.decode(lsp.WorkspaceSymbolParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.workspace_symbol(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/signatureHelp' {\n\t\t\tparams := json.decode(lsp.SignatureHelpParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.signature_help(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/completion' {\n\t\t\tparams := json.decode(lsp.CompletionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.completion(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/hover' {\n\t\t\tparams := json.decode(lsp.HoverParams, request.params) or { return w.wrap_error(err) }\n\t\t\thover_data := ls.hover(params) or {\n\t\t\t\tw.write_empty()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tw.write(hover_data)\n\t\t}\n\t\t'textDocument/foldingRange' {\n\t\t\tparams := json.decode(lsp.FoldingRangeParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.folding_range(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/definition' {\n\t\t\tparams := json.decode(lsp.TextDocumentPositionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.definition(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/typeDefinition' {\n\t\t\tparams := json.decode(lsp.TextDocumentPositionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.type_definition(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/references' {\n\t\t\tparams := json.decode(lsp.ReferenceParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.references(params))\n\t\t}\n\t\t'textDocument/implementation' {\n\t\t\tparams := json.decode(lsp.TextDocumentPositionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.implementation(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'workspace/didChangeWatchedFiles' {\n\t\t\tparams := json.decode(lsp.DidChangeWatchedFilesParams, request.params) or { return err }\n\t\t\tls.did_change_watched_files(params)\n\t\t}\n\t\t'textDocument/codeLens' {\n\t\t\tparams := json.decode(lsp.CodeLensParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.code_lens(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/inlayHint' {\n\t\t\tparams := json.decode(lsp.InlayHintParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.inlay_hints(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/prepareRename' {\n\t\t\tparams := json.decode(lsp.PrepareRenameParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.prepare_rename(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/rename' {\n\t\t\tparams := json.decode(lsp.RenameParams, request.params) or { return w.wrap_error(err) }\n\t\t\tw.write(ls.rename(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/documentLink' {}\n\t\t'textDocument/semanticTokens/full' {\n\t\t\tparams := json.decode(lsp.SemanticTokensParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.semantic_tokens(params.text_document, lsp.Range{}) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t})\n\t\t}\n\t\t'textDocument/semanticTokens/range' {\n\t\t\tparams := json.decode(lsp.SemanticTokensRangeParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.semantic_tokens(params.text_document, params.range) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t})\n\t\t}\n\t\t'textDocument/documentHighlight' {\n\t\t\tparams := json.decode(lsp.TextDocumentPositionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.document_highlight(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'textDocument/codeAction' {\n\t\t\tparams := json.decode(lsp.CodeActionParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.code_actions(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'workspace/executeCommand' {\n\t\t\tparams := json.decode(lsp.ExecuteCommandParams, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tls.execute_command(params)\n\t\t}\n\t\t'v-analyzer/viewStubTree' {\n\t\t\tparams := json.decode(lsp.TextDocumentIdentifier, request.params) or {\n\t\t\t\treturn w.wrap_error(err)\n\t\t\t}\n\t\t\tw.write(ls.view_stub_tree(params) or { return w.wrap_error(err) })\n\t\t}\n\t\t'$/cancelRequest' {\n\t\t\tloglib.info('got $/cancelRequest request')\n\t\t}\n\t\telse {\n\t\t\tloglib.with_fields({\n\t\t\t\t'method': request.method\n\t\t\t\t'params': request.params\n\t\t\t}).info('unhandled method call')\n\t\t}\n\t}\n\n\tloglib.with_fields({\n\t\t'method':   request.method\n\t\t'duration': watch.elapsed().str()\n\t}).log_one(.info, 'Request finished')\n}\n\npub fn (mut ls LanguageServer) register_intention(intention intentions.Intention) {\n\tls.intentions[intention.id] = intention\n}\n\npub fn (mut ls LanguageServer) register_compiler_quick_fix(quickfix intentions.CompilerQuickFix) {\n\tls.compiler_quick_fixes[quickfix.id] = quickfix\n}\n\n// launch_tool launches a tool with the same vroot as the language server\n// and returns the process.\n//\n// Example:\n// ```\n// p := ls.launch_tool('tool', 'arg1', 'arg2')!\n// defer {\n//   p.close()\n// }\n// p.wait()\n// ```\npub fn (mut ls LanguageServer) launch_tool(args ...string) !&os.Process {\n\tmut p := os.new_process(ls.paths.vexe)\n\tp.set_args(args)\n\tp.set_redirect_stdio()\n\treturn p\n}\n"
  },
  {
    "path": "src/server/progress/progress.v",
    "content": "module progress\n\nimport lsp\nimport server.protocol\n\npub struct Tracker {\npub mut:\n\tsupport_work_done_progress bool\n\tclient                     &protocol.Client = unsafe { nil }\n}\n\npub fn new_tracker(mut client protocol.Client) &Tracker {\n\treturn &Tracker{\n\t\tclient: client\n\t}\n}\n\npub fn (mut t Tracker) start(title string, message string, token lsp.ProgressToken) &WorkDone {\n\tmut wd := &WorkDone{\n\t\ttoken:  token\n\t\tclient: t.client\n\t}\n\n\tif !t.support_work_done_progress {\n\t\tt.client.show_message(message, .log)\n\t\treturn wd\n\t}\n\n\tif wd.token.empty() {\n\t\tnew_token := lsp.generate_progress_token()\n\t\tt.client.work_done_progress_create(token: new_token)\n\t\twd.token = new_token\n\t}\n\n\tt.client.progress(\n\t\ttoken: wd.token\n\t\tvalue: lsp.WorkDoneProgressPayload{\n\t\t\tkind:        'begin'\n\t\t\ttitle:       title\n\t\t\tmessage:     message\n\t\t\tpercentage:  0\n\t\t\tcancellable: false\n\t\t}\n\t)\n\n\treturn wd\n}\n\n@[heap]\npub struct WorkDone {\npub mut:\n\ttoken  lsp.ProgressToken\n\tclient &protocol.Client\n}\n\npub fn (mut wd WorkDone) progress(message string, percentage u32) {\n\tif wd.token.empty() {\n\t\treturn\n\t}\n\n\twd.client.progress(\n\t\ttoken: wd.token\n\t\tvalue: lsp.WorkDoneProgressPayload{\n\t\t\tkind:       'report'\n\t\t\tmessage:    message.trim_string_right('\\n')\n\t\t\tpercentage: percentage\n\t\t}\n\t)\n}\n\npub fn (mut wd WorkDone) end(message string) {\n\tif wd.token.empty() {\n\t\twd.client.show_message(message, .info)\n\t\treturn\n\t}\n\n\twd.client.progress(\n\t\ttoken: wd.token\n\t\tvalue: lsp.WorkDoneProgressPayload{\n\t\t\tkind:       'end'\n\t\t\tmessage:    message\n\t\t\tpercentage: 100\n\t\t}\n\t)\n}\n"
  },
  {
    "path": "src/server/protocol/Client.v",
    "content": "module protocol\n\nimport jsonrpc\nimport lsp\n\n@[heap]\npub struct Client {\nmut:\n\twr jsonrpc.ResponseWriter\n}\n\npub fn new_client(mut wr jsonrpc.ResponseWriter) &Client {\n\treturn &Client{\n\t\twr: wr\n\t}\n}\n\npub fn (mut c Client) work_done_progress_create(params lsp.WorkDoneProgressCreateParams) {\n\tc.wr.write_request('window/workDoneProgress/create', params)\n}\n\npub fn (mut c Client) progress(params lsp.ProgressParams) {\n\tc.wr.write_notify('$/progress', params)\n}\n\n// log_message sends a window/logMessage notification to the client\npub fn (mut c Client) log_message(message string, typ lsp.MessageType) {\n\t$if test {\n\t\tif c == unsafe { nil } {\n\t\t\treturn\n\t\t}\n\t}\n\tc.wr.write_notify('window/logMessage', lsp.LogMessageParams{\n\t\t@type:   typ\n\t\tmessage: message\n\t})\n}\n\n// show_message sends a window/showMessage notification to the client\npub fn (mut c Client) show_message(message string, typ lsp.MessageType) {\n\tc.wr.write_notify('window/showMessage', lsp.ShowMessageParams{\n\t\t@type:   typ\n\t\tmessage: message\n\t})\n}\n\npub fn (mut c Client) show_message_request(message string, actions []lsp.MessageActionItem, typ lsp.MessageType) {\n\tc.wr.write_notify('window/showMessageRequest', lsp.ShowMessageRequestParams{\n\t\t@type:   typ\n\t\tmessage: message\n\t\tactions: actions\n\t})\n}\n\npub fn (mut c Client) send_server_status(params lsp.ServerStatusParams) {\n\tc.wr.write_notify('experimental/serverStatus', params)\n}\n\npub fn (mut c Client) apply_edit(params lsp.ApplyWorkspaceEditParams) {\n\tc.wr.write_request('workspace/applyEdit', params)\n}\n"
  },
  {
    "path": "src/server/semantic/DumbAwareSemanticVisitor.v",
    "content": "module semantic\n\nimport lsp\nimport utils\nimport analyzer.psi\n\n// DumbAwareSemanticVisitor is a highly optimized visitor that collects information about\n// semantic tokens in a file based only on their syntax tree.\n// This annotator must not call resolve or use indexes.\npub struct DumbAwareSemanticVisitor {\n\tstart      u32  // start offset when request range is specified\n\tend        u32  // end offset when request range is specified\n\twith_range bool // whether request range is specified\n}\n\npub fn new_dumb_aware_semantic_visitor(range lsp.Range, containing_file &psi.PsiFile) DumbAwareSemanticVisitor {\n\tstart := utils.compute_offset(containing_file.source_text, range.start.line,\n\t\trange.start.character)\n\tend := utils.compute_offset(containing_file.source_text, range.end.line, range.end.character)\n\n\treturn DumbAwareSemanticVisitor{\n\t\twith_range: !range.is_empty()\n\t\tstart:      u32(start)\n\t\tend:        u32(end)\n\t}\n}\n\npub fn (v DumbAwareSemanticVisitor) accept(root psi.PsiElement) []SemanticToken {\n\tmut result := []SemanticToken{cap: 500}\n\tmut walker := psi.new_tree_walker(root.node())\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\trange := node.range()\n\t\tif v.with_range && (range.end_byte <= v.start || range.start_byte >= v.end) {\n\t\t\tcontinue\n\t\t}\n\n\t\tv.highlight_node(node, root, mut result)\n\t}\n\n\treturn result\n}\n\n@[inline]\nfn (_ DumbAwareSemanticVisitor) highlight_node(node psi.AstNode, root psi.PsiElement, mut result []SemanticToken) {\n\tcontaining_file := root.containing_file() or { return }\n\tsource_text := containing_file.source_text\n\n\tmatch node.type_name {\n\t\t.enum_field_definition {\n\t\t\tif first_child := node.first_child() {\n\t\t\t\tresult << element_to_semantic(first_child, .enum_member)\n\t\t\t}\n\t\t}\n\t\t.field_name {\n\t\t\tresult << element_to_semantic(node, .property)\n\t\t}\n\t\t.range_clause {\n\t\t\tif first_child := node.first_child() {\n\t\t\t\tresult << element_to_semantic(first_child, .property)\n\t\t\t}\n\t\t}\n\t\t.struct_field_declaration {\n\t\t\tif first_child := node.first_child() {\n\t\t\t\tif first_child.type_name != .embedded_definition {\n\t\t\t\t\tresult << element_to_semantic(first_child, .property)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.module_clause {\n\t\t\tif last_child := node.last_child() {\n\t\t\t\tresult << element_to_semantic(last_child, .namespace)\n\t\t\t}\n\t\t}\n\t\t.attribute {\n\t\t\t// '['\n\t\t\tif first_child := node.first_child() {\n\t\t\t\tresult << element_to_semantic(first_child, .decorator)\n\t\t\t}\n\t\t\t// ']'\n\t\t\tif last_child := node.last_child() {\n\t\t\t\tresult << element_to_semantic(last_child, .decorator)\n\t\t\t}\n\t\t}\n\t\t.key_value_attribute {\n\t\t\tif value_child := node.child_by_field_name('value') {\n\t\t\t\tif value_child.type_name == .identifier {\n\t\t\t\t\tresult << element_to_semantic(value_child, .string)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.qualified_type {\n\t\t\tif first_child := node.first_child() {\n\t\t\t\tresult << element_to_semantic(first_child, .namespace)\n\t\t\t}\n\t\t\tif last_child := node.last_child() {\n\t\t\t\tresult << element_to_semantic(last_child, .type_)\n\t\t\t}\n\t\t}\n\t\t.unknown {\n\t\t\ttext := node.text(source_text)\n\t\t\tif text == 'sql' {\n\t\t\t\tif parent := node.parent() {\n\t\t\t\t\tif parent.type_name == .sql_expression {\n\t\t\t\t\t\tresult << element_to_semantic(node, .keyword)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if text == 'chan' {\n\t\t\t\tif parent := node.parent() {\n\t\t\t\t\tif parent.type_name == .channel_type {\n\t\t\t\t\t\tresult << element_to_semantic(node, .keyword)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if text == 'thread' {\n\t\t\t\tif parent := node.parent() {\n\t\t\t\t\tif parent.type_name == .thread_type {\n\t\t\t\t\t\tresult << element_to_semantic(node, .keyword)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if text == 'implements' {\n\t\t\t\tif parent := node.parent() {\n\t\t\t\t\tif parent.type_name in [.struct_declaration, .interface_declaration,\n\t\t\t\t\t\t.implements_clause] {\n\t\t\t\t\t\tresult << element_to_semantic(node, .keyword)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.enum_declaration {\n\t\t\tif identifier := node.child_by_field_name('name') {\n\t\t\t\tresult << element_to_semantic(identifier, .enum_)\n\t\t\t}\n\t\t}\n\t\t.interface_declaration {\n\t\t\tif identifier := node.child_by_field_name('name') {\n\t\t\t\tresult << element_to_semantic(identifier, .interface_)\n\t\t\t}\n\t\t}\n\t\t.parameter_declaration, .receiver {\n\t\t\tif identifier := node.child_by_field_name('name') {\n\t\t\t\tif _ := node.child_by_field_name('mutability') {\n\t\t\t\t\tresult << element_to_semantic(identifier, .parameter, 'mutable')\n\t\t\t\t} else {\n\t\t\t\t\tresult << element_to_semantic(identifier, .parameter)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.reference_expression {\n\t\t\tdef := psi.node_to_var_definition(node, containing_file, none)\n\t\t\tif !isnil(def) {\n\t\t\t\tif def.is_mutable() {\n\t\t\t\t\tresult << element_to_semantic(node, .variable, 'mutable')\n\t\t\t\t} else {\n\t\t\t\t\tresult << element_to_semantic(node, .variable)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfirst_char := node.first_char(source_text)\n\t\t\tif first_char == `@` || first_char == `$` {\n\t\t\t\tresult << element_to_semantic(node, .property) // not a best variant...\n\t\t\t}\n\t\t}\n\t\t.const_definition {\n\t\t\tif name := node.child_by_field_name('name') {\n\t\t\t\tresult << element_to_semantic(name, .property) // not a best variant...\n\t\t\t}\n\t\t}\n\t\t.import_path {\n\t\t\tcount := node.child_count()\n\t\t\tfor i in 0 .. count {\n\t\t\t\tif child := node.child(i) {\n\t\t\t\t\tif child.type_name == .import_name {\n\t\t\t\t\t\tresult << element_to_semantic(child, .namespace)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.import_alias {\n\t\t\tif last_child := node.last_child() {\n\t\t\t\tresult << element_to_semantic(last_child, .namespace)\n\t\t\t}\n\t\t}\n\t\t.compile_time_if_expression {\n\t\t\tif condition := node.child_by_field_name('condition') {\n\t\t\t\thighlight_compile_time_condition(condition, mut result)\n\t\t\t}\n\t\t}\n\t\t.asm_statement {\n\t\t\tif first := node.first_child() {\n\t\t\t\tresult << element_to_semantic(first, .keyword)\n\t\t\t}\n\t\t\tif modifier := node.child_by_field_name('modifiers') {\n\t\t\t\tresult << element_to_semantic(modifier, .keyword)\n\t\t\t}\n\t\t\tif arch := node.child_by_field_name('arch') {\n\t\t\t\tresult << element_to_semantic(arch, .variable, 'readonly', 'defaultLibrary')\n\t\t\t}\n\t\t}\n\t\t.interpolation_opening, .interpolation_closing {\n\t\t\tresult << element_to_semantic(node, .keyword)\n\t\t}\n\t\t.generic_parameter {\n\t\t\tresult << element_to_semantic(node, .type_parameter)\n\t\t}\n\t\t.variadic_parameter {\n\t\t\tresult << element_to_semantic(node, .operator)\n\t\t}\n\t\t.global_var_definition {\n\t\t\tif identifier := node.child_by_field_name('name') {\n\t\t\t\tresult << element_to_semantic(identifier, .variable, 'global')\n\t\t\t}\n\t\t\tif modifiers := node.child_by_field_name('modifiers') {\n\t\t\t\tresult << element_to_semantic(modifiers, .keyword)\n\t\t\t}\n\t\t}\n\t\t.function_declaration {\n\t\t\tif first_child := node.child_by_field_name('name') {\n\t\t\t\tfirst_char := first_child.first_char(source_text)\n\t\t\t\tif first_char in [`@`, `$`] {\n\t\t\t\t\t// tweak highlighting for @lock/@rlock\n\t\t\t\t\tresult << element_to_semantic(first_child, .function)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t$if debug {\n\t\t\t\t// this useful for finding errors in parsing\n\t\t\t\tif node.type_name == .error {\n\t\t\t\t\tresult << element_to_semantic(node, .namespace, 'mutable')\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn highlight_compile_time_condition(node psi.AstNode, mut result []SemanticToken) {\n\tif node.type_name == .reference_expression {\n\t\tresult << element_to_semantic(node, .variable, 'readonly', 'defaultLibrary')\n\t} else if node.type_name == .binary_expression || node.type_name == .unary_expression {\n\t\tcount := node.child_count()\n\t\tfor i in 0 .. count {\n\t\t\tif child := node.child(i) {\n\t\t\t\thighlight_compile_time_condition(child, mut result)\n\t\t\t}\n\t\t}\n\t} else if node.type_name == .parenthesized_expression {\n\t\tif child := node.child(1) {\n\t\t\thighlight_compile_time_condition(child, mut result)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/server/semantic/ResolvingSemanticVisitor.v",
    "content": "module semantic\n\nimport lsp\nimport utils\nimport analyzer.psi\n\npub struct ResolveSemanticVisitor {\n\tstart      u32  // start offset when request range is specified\n\tend        u32  // end offset when request range is specified\n\twith_range bool // whether request range is specified\n}\n\npub fn new_resolve_semantic_visitor(range lsp.Range, containing_file &psi.PsiFile) ResolveSemanticVisitor {\n\tstart := utils.compute_offset(containing_file.source_text, range.start.line,\n\t\trange.start.character)\n\tend := utils.compute_offset(containing_file.source_text, range.end.line, range.end.character)\n\n\treturn ResolveSemanticVisitor{\n\t\twith_range: !range.is_empty()\n\t\tstart:      u32(start)\n\t\tend:        u32(end)\n\t}\n}\n\npub fn (v ResolveSemanticVisitor) accept(root psi.PsiElement) []SemanticToken {\n\tmut result := []SemanticToken{cap: 400}\n\tmut walker := psi.new_psi_tree_walker(root)\n\tdefer { walker.free() }\n\n\tfor {\n\t\tnode := walker.next() or { break }\n\t\trange := node.node().range()\n\t\tif v.with_range && (range.end_byte <= v.start || range.start_byte >= v.end) {\n\t\t\tcontinue\n\t\t}\n\n\t\tv.highlight_node(node, root, mut result)\n\t}\n\n\treturn result\n}\n\n@[inline]\nfn (_ ResolveSemanticVisitor) highlight_node(node psi.PsiElement, root psi.PsiElement, mut result []SemanticToken) {\n\tif node is psi.VarDefinition {\n\t\tif node.is_mutable() {\n\t\t\tif identifier := node.identifier() {\n\t\t\t\tresult << element_to_semantic(identifier.node(), .variable, 'mutable')\n\t\t\t}\n\t\t}\n\t}\n\n\tres, first_child := if node is psi.ReferenceExpression || node is psi.TypeReferenceExpression {\n\t\tres := (node as psi.ReferenceExpressionBase).resolve() or { return }\n\t\tfirst_child := (node as psi.PsiElement).node().first_child() or { return }\n\t\tres, first_child\n\t} else {\n\t\treturn\n\t}\n\n\tif res is psi.VarDefinition {\n\t\tmut mods := []string{}\n\t\tif res.is_mutable() {\n\t\t\tmods << 'mutable'\n\t\t}\n\t\tresult << element_to_semantic(first_child, .variable, ...mods)\n\t} else if res is psi.ConstantDefinition {\n\t\tresult << element_to_semantic(first_child, .property)\n\t} else if res is psi.InterfaceDeclaration {\n\t\tresult << element_to_semantic(first_child, .interface_)\n\t} else if res is psi.StructDeclaration {\n\t\tif res.name() != 'string' && res.module_name() != 'stubs.attributes' {\n\t\t\tresult << element_to_semantic(first_child, .struct_)\n\t\t}\n\t} else if res is psi.EnumDeclaration {\n\t\tresult << element_to_semantic(first_child, .enum_)\n\t} else if res is psi.FieldDeclaration {\n\t\tresult << element_to_semantic(first_child, .property)\n\t} else if res is psi.EnumFieldDeclaration {\n\t\tresult << element_to_semantic(first_child, .enum_member)\n\t} else if res is psi.ParameterDeclaration {\n\t\tmut mods := []string{}\n\t\tif res.is_mutable() {\n\t\t\tmods << 'mutable'\n\t\t}\n\t\tresult << element_to_semantic(first_child, .parameter, ...mods)\n\t} else if res is psi.Receiver {\n\t\tmut mods := []string{}\n\t\tif res.is_mutable() {\n\t\t\tmods << 'mutable'\n\t\t}\n\t\tresult << element_to_semantic(first_child, .parameter, ...mods)\n\t} else if res is psi.ImportSpec {\n\t\tresult << element_to_semantic(first_child, .namespace)\n\t} else if res is psi.ModuleClause {\n\t\tresult << element_to_semantic(first_child, .namespace)\n\t} else if res is psi.TypeAliasDeclaration {\n\t\tfile := res.containing_file() or { return }\n\t\tfrom_stubs := file.path.contains('stubs')\n\t\tif !from_stubs {\n\t\t\tresult << element_to_semantic(first_child, .type_)\n\t\t}\n\t} else if res is psi.GenericParameter {\n\t\tresult << element_to_semantic(first_child, .type_parameter)\n\t} else if res is psi.FunctionOrMethodDeclaration {\n\t\tresult << element_to_semantic(first_child, .function)\n\t} else if res is psi.GlobalVarDefinition {\n\t\tresult << element_to_semantic(first_child, .variable, 'global')\n\t} else if res is psi.EmbeddedDefinition {\n\t\tresult << element_to_semantic(first_child, .struct_)\n\t}\n}\n"
  },
  {
    "path": "src/server/semantic/SemanticToken.v",
    "content": "module semantic\n\nimport analyzer.psi\n\n@[json_as_number]\nenum SemanticTypes as u32 {\n\tnamespace\n\ttype_\n\tclass\n\tenum_\n\tinterface_\n\tstruct_\n\ttype_parameter\n\tparameter\n\tvariable\n\tproperty\n\tenum_member\n\tevent\n\tfunction\n\tmethod\n\tmacro\n\tkeyword\n\tmodifier\n\tcomment\n\tstring\n\tnumber\n\tregexp\n\toperator\n\tdecorator\n}\n\npub struct SemanticToken {\n\tline  u32\n\tstart u32\n\tlen   u32\n\ttyp   SemanticTypes\n\tmods  []string\n}\n\n@[inline]\nfn element_to_semantic(element psi.AstNode, typ SemanticTypes, modifiers ...string) SemanticToken {\n\tstart_point := element.start_point()\n\treturn SemanticToken{\n\t\tline:  start_point.row\n\t\tstart: start_point.column\n\t\tlen:   element.text_length()\n\t\ttyp:   typ\n\t\tmods:  modifiers\n\t}\n}\n"
  },
  {
    "path": "src/server/semantic/constants.v",
    "content": "module semantic\n\npub const semantic_types = [\n\t'namespace',\n\t'type',\n\t'class',\n\t'enum',\n\t'interface',\n\t'struct',\n\t'typeParameter',\n\t'parameter',\n\t'variable',\n\t'property',\n\t'enumMember',\n\t'event',\n\t'function',\n\t'method',\n\t'macro',\n\t'keyword',\n\t'modifier',\n\t'comment',\n\t'string',\n\t'number',\n\t'regexp',\n\t'operator',\n\t'decorator',\n]\npub const semantic_modifiers = [\n\t'declaration',\n\t'definition',\n\t'readonly',\n\t'static',\n\t'deprecated',\n\t'abstract',\n\t'async',\n\t'modification',\n\t'documentation',\n\t'defaultLibrary',\n\t'mutable',\n\t'global',\n]\n"
  },
  {
    "path": "src/server/semantic/encode.v",
    "content": "module semantic\n\n// encode encodes an array of semantic tokens into an array of u32s.\n// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens\n// for more information.\npub fn encode(tokens []SemanticToken) []u32 {\n\tmut result := tokens.clone()\n\n\t// By specification, the tokens must be sorted.\n\tresult.sort_with_compare(fn (left &SemanticToken, right &SemanticToken) int {\n\t\tif left.line != right.line {\n\t\t\tif left.line < right.line {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\tif left.line > right.line {\n\t\t\t\treturn 1\n\t\t\t}\n\t\t}\n\t\tif left.start < right.start {\n\t\t\treturn -1\n\t\t}\n\n\t\tif left.start > right.start {\n\t\t\treturn 1\n\t\t}\n\n\t\treturn 0\n\t})\n\n\tmut res := []u32{len: result.len * 5}\n\n\tmut cur := 0\n\tmut last := SemanticToken{}\n\tfor tok in result {\n\t\ttyp := u32(tok.typ)\n\t\tif cur == 0 {\n\t\t\tres[cur] = tok.line\n\t\t} else {\n\t\t\tres[cur] = tok.line - last.line\n\t\t}\n\t\tres[cur + 1] = tok.start\n\t\tif cur > 0 && res[cur] == 0 {\n\t\t\tres[cur + 1] = tok.start - last.start\n\t\t}\n\t\tres[cur + 2] = tok.len\n\t\tres[cur + 3] = typ\n\t\tres[cur + 4] = if 'mutable' in tok.mods {\n\t\t\tu32(0b010000000000)\n\t\t} else if 'global' in tok.mods {\n\t\t\tu32(0b0100000000000)\n\t\t} else {\n\t\t\tu32(0)\n\t\t} // temp hack\n\t\tcur += 5\n\t\tlast = tok\n\t}\n\n\treturn res[..cur]\n}\n"
  },
  {
    "path": "src/server/setup_test.v",
    "content": "module server\n\nimport os\nimport lsp\nimport loglib as _ // import to use __global `logger`\n\nconst default_vexe = @VEXE\nconst default_vroot = os.dir(default_vexe)\nconst default_vlib_root = os.join_path(default_vroot, 'vlib')\nconst default_vmodules_root = os.vmodules_dir()\n\nfn test_setup_default_vpaths() {\n\tmut ls := LanguageServer{}\n\tls.setup()\n\tassert ls.paths.vexe == default_vexe\n\tassert ls.paths.vroot == default_vroot\n\tassert ls.paths.vlib_root == default_vlib_root\n\tassert ls.paths.vmodules_root == default_vmodules_root\n}\n\nfn test_setup_custom_vpaths() {\n\tcustom_root := os.join_path(os.vtmp_dir(), 'v-analyzer-setup-test')\n\tcustom_root_uri := lsp.document_uri_from_path(custom_root)\n\tcfg_dir_path := os.join_path(custom_root, '.v-analyzer')\n\tcfg_path := os.join_path(cfg_dir_path, 'config.toml')\n\tos.mkdir_all(cfg_dir_path)!\n\tdefer {\n\t\tos.rmdir_all(cfg_dir_path) or {}\n\t}\n\n\t// Test custom_vroot with missing toolchain ==================================\n\t// Use single quotes for literal strings so that paths keep working on Windows.\n\tmut cfg_toml := \"custom_vroot = '${custom_root}'\"\n\tos.write_file(cfg_path, cfg_toml)!\n\n\t// Set output(io.Writer) for global loglib logger.\n\tlog_file_path := os.join_path(custom_root, 'log')\n\tos.write_file(log_file_path, '')!\n\tmut log_file := os.open_append(os.join_path(custom_root, 'log'))!\n\tlogger.out = log_file\n\n\t// Run setup\n\tmut ls := LanguageServer{}\n\tls.root_uri = custom_root_uri\n\tls.setup()\n\n\tlog_file.close()\n\tmut log_out := os.read_file(log_file_path)!\n\tprintln('Testlog custom_vroot missing toolchain:')\n\tprintln(log_out.trim_space())\n\tassert log_out.contains('Find custom VROOT path')\n\tassert log_out.contains('Using \"${custom_root}\" as toolchain')\n\tassert log_out.contains('Failed to find V standard library')\n\n\t// Test custom_vroot with existing toolchain =================================\n\tcfg_toml = \"custom_vroot = '${default_vroot}'\"\n\tos.write_file(cfg_path, cfg_toml)!\n\tos.write_file(log_file_path, '')!\n\tlog_file = os.open_append(os.join_path(custom_root, 'log'))!\n\tlogger.out = log_file\n\n\tls = LanguageServer{}\n\tls.root_uri = custom_root_uri\n\tls.setup()\n\n\tlog_file.close()\n\tlog_out = os.read_file(log_file_path)!\n\tprintln('Testlog custom_vroot existing toolchain:')\n\tprintln(log_out.trim_space())\n\tassert log_out.contains('Find custom VROOT path')\n\tassert log_out.contains('Using \"${default_vroot}\" as toolchain')\n\tassert !log_out.contains('Failed to find standard library path')\n}\n"
  },
  {
    "path": "src/server/tform/README.md",
    "content": "# Description\n\n`tform` module describes various transform functions from analyzer data to LSP data.\n"
  },
  {
    "path": "src/server/tform/tform.v",
    "content": "module tform\n\nimport lsp\nimport analyzer.psi\n\n// elements_to_locations converts an array of PsiElements to a slice of LSP locations.\npub fn elements_to_locations(elements []psi.PsiElement) []lsp.Location {\n\tmut locations := []lsp.Location{cap: elements.len}\n\tfor element in elements {\n\t\tfile := element.containing_file() or { continue }\n\t\trange := if element is psi.PsiNamedElement {\n\t\t\telement.identifier_text_range()\n\t\t} else {\n\t\t\telement.text_range()\n\t\t}\n\t\tlocations << lsp.Location{\n\t\t\turi:   file.uri()\n\t\t\trange: text_range_to_lsp_range(range)\n\t\t}\n\t}\n\treturn locations\n}\n\n// text_range_to_lsp_range converts a TextRange to an LSP Range.\npub fn text_range_to_lsp_range(pos psi.TextRange) lsp.Range {\n\treturn lsp.Range{\n\t\tstart: lsp.Position{\n\t\t\tline:      pos.line\n\t\t\tcharacter: pos.column\n\t\t}\n\t\tend:   lsp.Position{\n\t\t\tline:      pos.end_line\n\t\t\tcharacter: pos.end_column\n\t\t}\n\t}\n}\n\n// elements_to_text_edits converts an array of PsiElements to an array of LSP TextEdits.\n// If element is a PsiNamedElement, the edit will be applied to the identifier.\n// Otherwise, the edit will be applied to the entire element.\npub fn elements_to_text_edits(elements []psi.PsiElement, new_name string) []lsp.TextEdit {\n\tmut result := []lsp.TextEdit{cap: elements.len}\n\n\tfor element in elements {\n\t\trange := if element is psi.PsiNamedElement {\n\t\t\telement.identifier_text_range()\n\t\t} else {\n\t\t\telement.text_range()\n\t\t}\n\t\tresult << lsp.TextEdit{\n\t\t\trange:    text_range_to_lsp_range(range)\n\t\t\tnew_text: new_name\n\t\t}\n\t}\n\n\treturn result\n}\n\npub fn position_to_lsp_position(pos psi.Position) lsp.Position {\n\treturn lsp.Position{\n\t\tline:      pos.line\n\t\tcharacter: pos.character\n\t}\n}\n\npub fn lsp_position_to_position(pos lsp.Position) psi.Position {\n\treturn psi.Position{\n\t\tline:      pos.line\n\t\tcharacter: pos.character\n\t}\n}\n"
  },
  {
    "path": "src/server/workspace/ProjectResolver.v",
    "content": "module workspace\n\nimport os\nimport lsp\n\npub struct ProjectResolver {\n\tworkspace_root string\nmut:\n\tcache shared map[string]string\n}\n\npub fn ProjectResolver.new(workspace_root string) &ProjectResolver {\n\treturn &ProjectResolver{\n\t\tworkspace_root: os.real_path(workspace_root)\n\t\tcache:          map[string]string{}\n\t}\n}\n\npub fn (mut p ProjectResolver) resolve(uri lsp.DocumentUri) string {\n\tfilepath := os.real_path(uri.path())\n\tdir := os.dir(filepath)\n\n\trlock p.cache {\n\t\tif cached := p.cache[dir] {\n\t\t\treturn cached\n\t\t}\n\t}\n\n\troot := p.find_root(dir)\n\n\tlock p.cache {\n\t\tp.cache[dir] = root\n\t}\n\n\treturn root\n}\n\npub fn (mut p ProjectResolver) clear() {\n\tlock p.cache {\n\t\tp.cache.clear()\n\t}\n}\n\nfn (p &ProjectResolver) find_root(start_dir string) string {\n\tmut curr := start_dir\n\thome_dir := os.home_dir()\n\n\tfor {\n\t\tif os.exists(os.join_path(curr, 'v.mod')) || os.is_dir(os.join_path(curr, '.git'))\n\t\t\t|| curr == p.workspace_root {\n\t\t\treturn curr\n\t\t}\n\n\t\tparent := os.dir(curr)\n\t\tif curr == home_dir || parent == curr {\n\t\t\tbreak\n\t\t}\n\t\tcurr = parent\n\t}\n\n\treturn if start_dir.starts_with(p.workspace_root) {\n\t\tp.workspace_root\n\t} else {\n\t\tstart_dir\n\t}\n}\n"
  },
  {
    "path": "src/streams/streams.v",
    "content": "module streams\n\nimport term\nimport net\nimport os\nimport io\nimport loglib\n\nfn C._setmode(int, int)\n\nconst content_length = 'Content-Length: '\n\npub fn new_stdio_stream() io.ReaderWriter {\n\tstream := &StdioStream{}\n\t$if windows {\n\t\t// 0x8000 = _O_BINARY from <fcntl.h>\n\t\t// windows replaces \\n => \\r\\n, so \\r\\n will be replaced to \\r\\r\\n\n\t\t// binary mode prevents this\n\t\tC._setmode(C._fileno(C.stdout), 0x8000)\n\t}\n\treturn stream\n}\n\nstruct StdioStream {\nmut:\n\tstdin  os.File = os.stdin()\n\tstdout os.File = os.stdout()\n}\n\npub fn (mut stream StdioStream) write(buf []u8) !int {\n\tdefer {\n\t\tstream.stdout.flush()\n\t}\n\treturn stream.stdout.write(buf)\n}\n\npub fn (mut stream StdioStream) read(mut buf []u8) !int {\n\tmut header_len := 0\n\tmut conlen := 0\n\tfor {\n\t\tlen := read_line(stream.stdin, mut buf) or { return err }\n\t\tst := buf.len - len\n\t\tline := buf[st..].bytestr()\n\n\t\tbuf << `\\r`\n\t\tbuf << `\\n`\n\t\theader_len = len + 2\n\n\t\tif len == 0 {\n\t\t\t// encounter empty line ('\\r\\n') in header, header end\n\t\t\tbreak\n\t\t} else if line.starts_with(content_length) {\n\t\t\tconlen = line.all_after(content_length).int()\n\t\t}\n\t}\n\n\tmut body := []u8{len: conlen}\n\tread_cnt := stream.stdin.read(mut body) or { return err }\n\tif read_cnt != conlen {\n\t\treturn IError(io.Eof{})\n\t}\n\tbuf << body\n\n\treturn header_len + conlen\n}\n\nfn read_line(file &os.File, mut buf []u8) !int {\n\tmut len := 0\n\tmut temp := []u8{len: 256, cap: 256}\n\tfor {\n\t\tread_cnt := file.read_bytes_with_newline(mut temp) or { return err }\n\t\tlen += read_cnt\n\t\tbuf << temp[0..read_cnt]\n\t\tif read_cnt == 0 {\n\t\t\treturn if len == 0 {\n\t\t\t\tIError(io.Eof{})\n\t\t\t} else {\n\t\t\t\tlen\n\t\t\t}\n\t\t}\n\t\tif buf.len > 0 && buf.last() == `\\n` {\n\t\t\tbuf.pop()\n\t\t\tlen--\n\t\t\t// check is it just '\\n' or '\\r\\n'\n\t\t\tif len > 0 && buf.last() == `\\r` {\n\t\t\t\tbuf.pop()\n\t\t\t\tlen--\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn len\n}\n\nconst base_ip = '127.0.0.1'\n\npub fn new_socket_stream_server(port int, log bool) !io.ReaderWriter {\n\tserver_label := 'v-analyzer-server'\n\n\taddress := '${base_ip}:${port}'\n\tmut listener := net.listen_tcp(.ip, address)!\n\n\tif log {\n\t\teprintln(term.yellow('Warning: TCP connection is used primarily for debugging purposes only \\n         and may have performance issues. Use it on your own risk.\\n'))\n\t\tprintln('[${server_label}] : Established connection at ${address}\\n')\n\t}\n\n\tmut conn := listener.accept() or {\n\t\tlistener.close() or {}\n\t\treturn err\n\t}\n\n\tmut reader := io.new_buffered_reader(reader: conn, cap: 1024 * 1024)\n\tconn.set_blocking(true) or {}\n\n\tmut stream := &SocketStream{\n\t\tlog_label: server_label\n\t\tlog:       log\n\t\tport:      port\n\t\tconn:      conn\n\t\treader:    reader\n\t}\n\n\treturn stream\n}\n\nfn new_socket_stream_client(port int) !io.ReaderWriter {\n\taddress := '${base_ip}:${port}'\n\tmut conn := net.dial_tcp(address)!\n\tmut reader := io.new_buffered_reader(reader: conn, cap: 1024 * 1024)\n\tconn.set_blocking(true) or {}\n\n\tmut stream := &SocketStream{\n\t\tlog_label: 'v-analyzer-client'\n\t\tlog:       false\n\t\tport:      port\n\t\tconn:      conn\n\t\treader:    reader\n\t}\n\treturn stream\n}\n\nstruct SocketStream {\n\tlog_label string = 'v-analyzer'\n\tlog       bool   = true\nmut:\n\tconn   &net.TcpConn       = &net.TcpConn(net.listen_tcp(.ip, '80')!)\n\treader &io.BufferedReader = unsafe { nil }\npub mut:\n\tport  int = 5007\n\tdebug bool\n}\n\npub fn (mut stream SocketStream) write(buf []u8) !int {\n\t// TODO: should be an interceptor\n\t$if !test {\n\t\tif stream.log {\n\t\t\tloglib.trace('${term.bg_green('Sent data →')} : ${buf.bytestr()}\\n')\n\t\t}\n\t}\n\n\treturn stream.conn.write(buf)\n}\n\nconst newlines = [u8(`\\r`), `\\n`]\n\n@[manualfree]\npub fn (mut stream SocketStream) read(mut buf []u8) !int {\n\tmut conlen := 0\n\tmut header_len := 0\n\n\tfor {\n\t\t// read header line\n\t\tgot_header := stream.reader.read_line() or { return IError(io.Eof{}) }\n\t\tbuf << got_header.bytes()\n\t\tbuf << newlines\n\t\theader_len = got_header.len + 2\n\n\t\tif got_header.len == 0 {\n\t\t\t// encounter empty line ('\\r\\n') in header, header end\n\t\t\tbreak\n\t\t} else if got_header.starts_with(content_length) {\n\t\t\tconlen = got_header.all_after(content_length).int()\n\t\t}\n\t}\n\n\tif conlen > 0 {\n\t\tmut rbody := []u8{len: conlen}\n\t\tdefer {\n\t\t\tunsafe { rbody.free() }\n\t\t}\n\n\t\tfor read_data_len := 0; read_data_len != conlen; {\n\t\t\tread_data_len = stream.reader.read(mut rbody) or { return IError(io.Eof{}) }\n\t\t}\n\n\t\tbuf << rbody\n\t}\n\n\t$if !test {\n\t\tif stream.log {\n\t\t\tloglib.trace('${term.green('Received data ←')} : ${buf.bytestr()}\\n')\n\t\t}\n\t}\n\treturn conlen + header_len\n}\n"
  },
  {
    "path": "src/testing/Benchmark.v",
    "content": "module testing\n\nimport time\n\npub struct Benchmark {\nmut:\n\tname  string\n\twatch time.StopWatch\n}\n\npub fn (mut b Benchmark) start() {\n\tb.watch.start()\n}\n\npub fn (mut b Benchmark) stop() {\n\tb.watch.stop()\n}\n\npub fn (b &Benchmark) print_results() {\n\tprintln('Benchmark: ' + b.name)\n\tprintln('Time: ' + b.watch.elapsed().str())\n}\n"
  },
  {
    "path": "src/testing/BenchmarkRunner.v",
    "content": "module testing\n\npub struct BenchmarkRunner {\nmut:\n\tbenchmarks []&Benchmark\npub mut:\n\tlast_fixture &Fixture\n}\n\npub fn (mut b BenchmarkRunner) create_or_reuse_fixture() &Fixture {\n\tif !isnil(b.last_fixture) {\n\t\treturn b.last_fixture\n\t}\n\n\tmut fixture := new_fixture()\n\tfixture.initialize(false) or {\n\t\tprintln('Cannot initialize fixture: ${err}')\n\t\treturn fixture\n\t}\n\n\tb.last_fixture = fixture\n\treturn fixture\n}\n\npub fn (mut b BenchmarkRunner) bench(name string, bench_func fn (mut bench Benchmark, mut fixture Fixture) !) {\n\tmut fixture := b.create_or_reuse_fixture()\n\n\tmut bench := &Benchmark{\n\t\tname: name\n\t}\n\tb.benchmarks << bench\n\tbench_func(mut bench, mut fixture) or { println('Benchmark failed: ${err}') }\n}\n"
  },
  {
    "path": "src/testing/Test.v",
    "content": "module testing\n\nimport term\nimport lsp\nimport time\nimport strings\n\npub type TestFunc = fn (mut test Test, mut fixture Fixture) !\n\npub enum TestState {\n\tpassed\n\tfailed\n\tskipped\n}\n\npub struct Test {\nmut:\n\tfixture     &Fixture = unsafe { nil }\n\tname        string\n\tfunc        TestFunc = unsafe { nil }\n\tstate       TestState\n\tmessage     string\n\twith_stdlib bool\n\tduration    time.Duration\n}\n\npub fn (mut t Test) run(mut fixture Fixture) {\n\twatch := time.new_stopwatch(auto_start: true)\n\tt.fixture = fixture\n\tt.func(mut t, mut fixture) or {}\n\tt.duration = watch.elapsed()\n\tt.print()\n}\n\npub fn (mut t Test) fail(msg string) ! {\n\tt.state = .failed\n\tt.message = msg\n\treturn error(msg)\n}\n\npub fn (mut t Test) assert_eq[T](left T, right T) ! {\n\tif left != right {\n\t\tt.fail('expected ${left}, but got ${right}')!\n\t}\n}\n\npub fn (mut t Test) assert_definition_name(location lsp.LocationLink, name string) ! {\n\tlink_text := t.fixture.text_at_range(location.target_selection_range)\n\tif link_text != name {\n\t\tt.fail('expected definition \"${name}\", but got \"${link_text}\"')!\n\t}\n}\n\npub fn (mut t Test) assert_no_definition(locations []lsp.LocationLink) ! {\n\tif locations.len != 0 {\n\t\tt.fail('expected no definition, but got ${locations.len}')!\n\t}\n}\n\npub fn (mut t Test) assert_has_definition(locations []lsp.LocationLink) ! {\n\tif locations.len == 0 {\n\t\tt.fail('no definition found')!\n\t}\n}\n\npub fn (mut t Test) assert_has_completion_with_label(items []lsp.CompletionItem, name string) ! {\n\tfor item in items {\n\t\tif item.label == name {\n\t\t\treturn\n\t\t}\n\t}\n\n\tt.fail('expected completion \"${name}\" not found')!\n}\n\npub fn (mut t Test) assert_has_only_completion_with_labels(items []lsp.CompletionItem, names ...string) ! {\n\tif items.len != names.len {\n\t\tt.fail('expected ${names.len} completions, but got ${items.len}')!\n\t}\n\n\tfor name in names {\n\t\tt.assert_has_completion_with_label(items, name)!\n\t}\n}\n\npub fn (mut t Test) assert_has_completion_with_insert_text(items []lsp.CompletionItem, name string) ! {\n\tif items.len == 0 {\n\t\tt.fail('no completions found')!\n\t}\n\n\tfor item in items {\n\t\tif item.insert_text == name {\n\t\t\treturn\n\t\t}\n\t}\n\n\tt.fail('expected completion \"${name}\" not found')!\n}\n\npub fn (mut t Test) assert_no_completion_with_insert_text(items []lsp.CompletionItem, name string) ! {\n\tfor item in items {\n\t\tif item.insert_text == name {\n\t\t\tt.fail('unexpected completion \"${name}\" found')!\n\t\t}\n\t}\n}\n\npub fn (mut t Test) assert_no_completion_with_label(items []lsp.CompletionItem, name string) ! {\n\tfor item in items {\n\t\tif item.label == name {\n\t\t\tt.fail('unexpected completion \"${name}\" found')!\n\t\t}\n\t}\n}\n\npub fn (mut t Test) assert_has_implementation_with_name(items []lsp.Location, name string) ! {\n\tfor item in items {\n\t\tlink_text := t.fixture.text_at_range(item.range)\n\t\tif link_text == name {\n\t\t\treturn\n\t\t}\n\t}\n\n\tt.fail('expected implementation \"${name}\" not found')!\n}\n\npub fn (mut t Test) assert_no_implementation_with_name(items []lsp.Location, name string) ! {\n\tfor item in items {\n\t\tlink_text := t.fixture.text_at_range(item.range)\n\t\tif link_text == name {\n\t\t\tt.fail('unexpected implementation \"${name}\" found')!\n\t\t}\n\t}\n}\n\npub fn (mut t Test) assert_has_super_with_name(items []lsp.Location, name string) ! {\n\tfor item in items {\n\t\tlink_text := t.fixture.text_at_range(item.range)\n\t\tif link_text == name {\n\t\t\treturn\n\t\t}\n\t}\n\n\tt.fail('expected super \"${name}\" not found')!\n}\n\npub fn (mut t Test) assert_no_super_with_name(items []lsp.Location, name string) ! {\n\tfor item in items {\n\t\tlink_text := t.fixture.text_at_range(item.range)\n\t\tif link_text == name {\n\t\t\tt.fail('unexpected super \"${name}\" found')!\n\t\t}\n\t}\n}\n\npub fn (mut t Test) assert_uri(left lsp.DocumentUri, right lsp.DocumentUri) ! {\n\tleft_normalized := left.normalize()\n\tright_normalized := right.normalize()\n\tif left_normalized.compare(right_normalized) != 0 {\n\t\tt.fail('expected ${left_normalized}, but got ${right_normalized}')!\n\t}\n}\n\npub fn (mut t Test) assert_uri_from_stdlib(left lsp.DocumentUri, filename string) ! {\n\tif !left.contains('vlib') {\n\t\tt.fail('expected ${left} to be inside \"vlib\"')!\n\t}\n\n\tif !left.ends_with(filename) {\n\t\tt.fail('expected ${left} to end with ${filename} but got ${left}')!\n\t}\n}\n\npub fn (mut t Test) assert_uri_from_stubs(left lsp.DocumentUri, filename string) ! {\n\tif !left.contains('stubs') {\n\t\tt.fail('expected ${left} to be inside \"stubs\"')!\n\t}\n\n\tif !left.ends_with(filename) {\n\t\tt.fail('expected ${left} to end with ${filename} but got ${left}')!\n\t}\n}\n\npub fn (t Test) print() {\n\tmut sb := strings.new_builder(100)\n\tsb.write_string('${t.duration:10} ')\n\n\tif t.state == .failed {\n\t\tsb.write_string(term.red('[FAILED] '))\n\t\tsb.write_string(t.name)\n\t\tsb.write_string('\\n')\n\t\tsb.write_string('      ${t.message}\\n')\n\t} else if t.state == .passed {\n\t\tsb.write_string(term.green('[PASSED] '))\n\t\tsb.write_string(t.name)\n\t\tsb.write_string('\\n')\n\t}\n\n\tprint(sb.str())\n}\n"
  },
  {
    "path": "src/testing/TestFixture.v",
    "content": "module testing\n\nimport os\nimport testing.client\nimport lsp\nimport jsonrpc\nimport server\nimport analyzer\n\npub const temp_path = os.join_path(os.temp_dir(), 'v-analyzer-test')\n\nstruct TestFile {\n\tpath    string\n\tcontent []string\n\tcaret   lsp.Position\n}\n\npub fn (t TestFile) uri() lsp.DocumentUri {\n\treturn lsp.document_uri_from_path(t.path)\n}\n\n@[heap; noinit]\npub struct Fixture {\nmut:\n\tls           &server.LanguageServer = unsafe { nil }\n\tstream       &client.TestStream     = unsafe { nil }\n\tserver       &jsonrpc.Server        = unsafe { nil }\n\ttest_client  client.TestClient\n\tcurrent_file TestFile\n\n\topened_files []string\n}\n\npub fn new_fixture() &Fixture {\n\tindexing_mng := analyzer.IndexingManager.new()\n\tmut ls := server.LanguageServer.new(indexing_mng)\n\n\tmut stream := &client.TestStream{}\n\tmut jsonprc_server := &jsonrpc.Server{\n\t\tstream:  stream\n\t\thandler: ls\n\t}\n\n\tmut test_client := client.TestClient{\n\t\tserver: jsonprc_server\n\t\tstream: stream\n\t}\n\n\treturn &Fixture{\n\t\tls:          ls\n\t\tstream:      stream\n\t\tserver:      jsonprc_server\n\t\ttest_client: test_client\n\t}\n}\n\npub fn (mut t Fixture) initialize(with_stdlib bool) !lsp.InitializeResult {\n\tos.mkdir_all(temp_path)!\n\n\tmut options := ['no-index-save', 'no-diagnostics']\n\tif !with_stdlib {\n\t\toptions << 'no-stdlib'\n\t}\n\n\tresult := t.test_client.send[lsp.InitializeParams, lsp.InitializeResult]('initialize', lsp.InitializeParams{\n\t\tprocess_id:             75556\n\t\tclient_info:            lsp.ClientInfo{\n\t\t\tname:    'Testing'\n\t\t\tversion: '0.0.1'\n\t\t}\n\t\troot_uri:               lsp.document_uri_from_path(temp_path)\n\t\troot_path:              temp_path\n\t\tinitialization_options: options.join(' ')\n\t\tcapabilities:           lsp.ClientCapabilities{}\n\t\ttrace:                  ''\n\t\tworkspace_folders:      []\n\t})!\n\n\treturn result\n}\n\npub fn (mut t Fixture) initialized() ! {\n\tt.test_client.send[jsonrpc.Null, jsonrpc.Null]('initialized', jsonrpc.Null{})!\n}\n\npub fn (mut t Fixture) configure_by_file(path string) ! {\n\trel_path := 'testdata/${path}'\n\tcontent := os.read_file(rel_path)!\n\tprepared_text := content + '\\n\\n' // add extra lines to make sure the caret is not at the end of the file\n\tprepared_content := prepared_text.replace('/*caret*/', '')\n\tabs_path := os.join_path(temp_path, path)\n\tdir_path := os.dir(abs_path)\n\tos.mkdir_all(dir_path)!\n\tos.write_file(abs_path, prepared_content)!\n\n\tif t.current_file.path == abs_path {\n\t\tt.close_file(t.current_file.path)\n\t}\n\n\tt.current_file = TestFile{\n\t\tpath:    abs_path\n\t\tcontent: prepared_content.split_into_lines()\n\t\tcaret:   t.caret_pos(prepared_text)\n\t}\n\n\tt.send_open_current_file_request()!\n}\n\npub fn (mut t Fixture) configure_by_text(filename string, text string) ! {\n\tprepared_text := text + '\\n\\n' // add extra lines to make sure the caret is not at the end of the file\n\tcontent := prepared_text.replace('/*caret*/', '')\n\tabs_path := os.join_path(temp_path, filename)\n\tabs_path_without_name := os.dir(abs_path)\n\tos.mkdir_all(abs_path_without_name)!\n\tos.write_file(abs_path, content)!\n\n\tif t.current_file.path == abs_path {\n\t\tt.close_file(t.current_file.path)\n\t}\n\n\tt.current_file = TestFile{\n\t\tpath:    abs_path\n\t\tcontent: content.split_into_lines()\n\t\tcaret:   t.caret_pos(prepared_text)\n\t}\n\n\tt.send_open_current_file_request()!\n}\n\nfn (mut t Fixture) send_open_current_file_request() ! {\n\tt.test_client.send[lsp.DidOpenTextDocumentParams, jsonrpc.Null]('textDocument/didOpen', lsp.DidOpenTextDocumentParams{\n\t\ttext_document: lsp.TextDocumentItem{\n\t\t\turi:         lsp.document_uri_from_path(t.current_file.path)\n\t\t\tlanguage_id: 'v'\n\t\t\tversion:     1\n\t\t\ttext:        t.current_file.content.join('\\n')\n\t\t}\n\t}) or {}\n\n\tt.test_client.send[lsp.DidChangeTextDocumentParams, jsonrpc.Null]('textDocument/didChange', lsp.DidChangeTextDocumentParams{\n\t\ttext_document:   lsp.VersionedTextDocumentIdentifier{\n\t\t\turi:     lsp.document_uri_from_path(t.current_file.path)\n\t\t\tversion: 1\n\t\t}\n\t\tcontent_changes: [\n\t\t\tlsp.TextDocumentContentChangeEvent{\n\t\t\t\ttext: t.current_file.content.join('\\n')\n\t\t\t},\n\t\t]\n\t}) or {}\n\n\tt.test_client.send[lsp.DidChangeWatchedFilesParams, jsonrpc.Null]('workspace/didChangeWatchedFiles', lsp.DidChangeWatchedFilesParams{\n\t\tchanges: [\n\t\t\tlsp.FileEvent{\n\t\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t\t\ttyp: lsp.FileChangeType.created\n\t\t\t},\n\t\t]\n\t}) or {}\n}\n\npub fn (mut t Fixture) definition_at_cursor() []lsp.LocationLink {\n\treturn t.definition(t.current_caret_pos())\n}\n\npub fn (mut t Fixture) definition(pos lsp.Position) []lsp.LocationLink {\n\tlinks := t.test_client.send[lsp.TextDocumentPositionParams, []lsp.LocationLink]('textDocument/definition', lsp.TextDocumentPositionParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t\tposition:      pos\n\t}) or { []lsp.LocationLink{} }\n\n\treturn links\n}\n\npub fn (mut t Fixture) complete_at_cursor() []lsp.CompletionItem {\n\treturn t.complete(t.current_caret_pos())\n}\n\npub fn (mut t Fixture) complete(pos lsp.Position) []lsp.CompletionItem {\n\titems := t.test_client.send[lsp.CompletionParams, []lsp.CompletionItem]('textDocument/completion', lsp.CompletionParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t\tposition:      pos\n\t\tcontext:       lsp.CompletionContext{\n\t\t\ttrigger_kind: .invoked\n\t\t}\n\t}) or { []lsp.CompletionItem{} }\n\n\treturn items\n}\n\npub fn (mut t Fixture) compute_inlay_hints() []lsp.InlayHint {\n\thints := t.test_client.send[lsp.InlayHintParams, []lsp.InlayHint]('textDocument/inlayHint', lsp.InlayHintParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t}) or { []lsp.InlayHint{} }\n\n\treturn hints\n}\n\npub fn (mut t Fixture) compute_semantic_tokens() lsp.SemanticTokens {\n\ttokens := t.test_client.send[lsp.SemanticTokensParams, lsp.SemanticTokens]('textDocument/semanticTokens/full', lsp.SemanticTokensParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t}) or { lsp.SemanticTokens{} }\n\n\treturn tokens\n}\n\npub fn (mut t Fixture) implementation_at_cursor() []lsp.Location {\n\treturn t.implementation(t.current_caret_pos())\n}\n\npub fn (mut t Fixture) implementation(pos lsp.Position) []lsp.Location {\n\tlinks := t.test_client.send[lsp.TextDocumentPositionParams, []lsp.Location]('textDocument/implementation', lsp.TextDocumentPositionParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t\tposition:      pos\n\t}) or { []lsp.Location{} }\n\n\treturn links\n}\n\npub fn (mut t Fixture) supers_at_cursor() []lsp.Location {\n\treturn t.supers(t.current_caret_pos())\n}\n\npub fn (mut t Fixture) supers(pos lsp.Position) []lsp.Location {\n\treturn t.implementation(pos)\n}\n\npub fn (mut t Fixture) documentation_at_cursor() ?lsp.Hover {\n\treturn t.documentation(t.current_caret_pos())\n}\n\npub fn (mut t Fixture) documentation(pos lsp.Position) ?lsp.Hover {\n\thover := t.test_client.send[lsp.HoverParams, lsp.Hover]('textDocument/hover', lsp.HoverParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(t.current_file.path)\n\t\t}\n\t\tposition:      pos\n\t}) or { return none }\n\n\treturn hover\n}\n\npub fn (mut t Fixture) close_file(path string) {\n\tt.test_client.send[lsp.DidCloseTextDocumentParams, jsonrpc.Null]('textDocument/didClose', lsp.DidCloseTextDocumentParams{\n\t\ttext_document: lsp.TextDocumentIdentifier{\n\t\t\turi: lsp.document_uri_from_path(path)\n\t\t}\n\t}) or {}\n}\n\npub fn (mut t Fixture) current_file_uri() lsp.DocumentUri {\n\treturn lsp.document_uri_from_path(t.current_file.path)\n}\n\npub fn (mut t Fixture) text_at_range(range lsp.Range) string {\n\tlines := t.current_file.content\n\tstart := range.start\n\tend := range.end\n\n\tif start.line == end.line {\n\t\treturn lines[start.line][start.character..end.character]\n\t}\n\n\tmut result := lines[start.line][start.character..]\n\n\tfor line in lines[start.line + 1..end.line] {\n\t\tresult += line\n\t}\n\n\tresult += lines[end.line][..end.character]\n\n\treturn result\n}\n\npub fn (mut t Fixture) current_caret_pos() lsp.Position {\n\treturn t.current_file.caret\n}\n\npub fn (mut t Fixture) caret_pos(file string) lsp.Position {\n\tfor index, line in file.split_into_lines() {\n\t\tif line.contains('/*caret*/') {\n\t\t\treturn lsp.Position{\n\t\t\t\tline:      index\n\t\t\t\tcharacter: line.index('/*caret*/') or { 0 }\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lsp.Position{\n\t\tline:      0\n\t\tcharacter: 0\n\t}\n}\n"
  },
  {
    "path": "src/testing/Tester.v",
    "content": "module testing\n\nimport os\nimport lsp\nimport time\nimport term\nimport loglib\nimport analyzer.psi\n\npub struct TesterStats {\npub:\n\tpassed   int\n\tfailed   int\n\tskipped  int\n\tduration time.Duration\n}\n\npub fn (s TesterStats) print() {\n\tprintln('${term.bold('Passed')}: ${s.passed}, ${term.bold('Failed')}: ${s.failed}, ${term.bold('Skipped')}: ${s.skipped}')\n\tprintln('${term.bold('Duration')}: ${s.duration}')\n}\n\npub fn (s TesterStats) merge(other TesterStats) TesterStats {\n\treturn TesterStats{\n\t\tpassed:   s.passed + other.passed\n\t\tfailed:   s.failed + other.failed\n\t\tskipped:  s.skipped + other.skipped\n\t\tduration: s.duration + other.duration\n\t}\n}\n\npub struct Tester {\npub:\n\tname string\nmut:\n\ttests             []&Test\n\tlast_fixture      &Fixture = unsafe { nil }\n\tlast_slow_fixture &Fixture = unsafe { nil }\n}\n\npub fn with_name(name string) Tester {\n\treturn Tester{\n\t\tname: name\n\t}\n}\n\npub fn (mut t Tester) failed_tests() []&Test {\n\treturn t.tests.filter(it.state == .failed)\n}\n\npub fn (mut t Tester) create_or_reuse_fixture(with_stdlib bool) &Fixture {\n\tif with_stdlib {\n\t\tif !isnil(t.last_slow_fixture) {\n\t\t\treturn t.last_slow_fixture\n\t\t}\n\t} else {\n\t\tif !isnil(t.last_fixture) {\n\t\t\treturn t.last_fixture\n\t\t}\n\t}\n\n\tloglib.set_level(.warn) // we don't want to see info messages in tests\n\n\tmut fixture := new_fixture()\n\tfixture.initialize(with_stdlib) or {\n\t\tprintln('Cannot initialize fixture: ${err}')\n\t\treturn fixture\n\t}\n\n\tfixture.initialized() or {\n\t\tprintln('Cannot run initialized request: ${err}')\n\t\treturn fixture\n\t}\n\n\tif with_stdlib {\n\t\tt.last_slow_fixture = fixture\n\t} else {\n\t\tt.last_fixture = fixture\n\t}\n\treturn fixture\n}\n\npub fn (mut t Tester) run(run_only string) {\n\tmut fixture := t.create_or_reuse_fixture(false)\n\n\tfor mut test in t.tests {\n\t\tif run_only != '' && test.name != run_only {\n\t\t\ttest.state = .skipped\n\t\t\tcontinue\n\t\t}\n\n\t\tif test.with_stdlib {\n\t\t\tmut fixture_with_stdlib := t.create_or_reuse_fixture(true)\n\t\t\ttest.run(mut fixture_with_stdlib)\n\t\t\tcontinue\n\t\t}\n\t\ttest.run(mut fixture)\n\t}\n}\n\npub fn (t Tester) stats() TesterStats {\n\tmut passed := 0\n\tmut failed := 0\n\tmut skipped := 0\n\tmut duration := 0\n\n\tfor test in t.tests {\n\t\tif test.state == .skipped {\n\t\t\tskipped += 1\n\t\t} else if test.state == .failed {\n\t\t\tfailed += 1\n\t\t} else {\n\t\t\tpassed += 1\n\t\t}\n\n\t\tduration += test.duration\n\t}\n\n\treturn TesterStats{\n\t\tpassed:   passed\n\t\tfailed:   failed\n\t\tskipped:  skipped\n\t\tduration: duration\n\t}\n}\n\npub fn (mut t Tester) test(name string, test_func TestFunc) {\n\tmut test := &Test{\n\t\tname: name\n\t\tfunc: test_func\n\t}\n\tt.tests << test\n}\n\npub fn (mut t Tester) slow_test(name string, test_func TestFunc) {\n\tmut test := &Test{\n\t\tname:        name\n\t\tfunc:        test_func\n\t\twith_stdlib: true\n\t}\n\tt.tests << test\n}\n\npub fn (mut t Tester) type_test(name string, filepath string) {\n\tmut test := &Test{\n\t\tname: name\n\t}\n\tt.tests << test\n\n\ttest.func = fn [filepath] (mut test Test, mut fixture Fixture) ! {\n\t\tfixture.configure_by_file(filepath) or {\n\t\t\tprintln('Cannot configure fixture: ${err}')\n\t\t\treturn error('Cannot configure fixture: ${err}')\n\t\t}\n\t\tfile := fixture.ls.get_file(fixture.current_file.uri()) or {\n\t\t\treturn error('File not found: ${fixture.current_file.uri()}')\n\t\t}\n\n\t\tmut expr_calls := []psi.CallExpression{}\n\t\tmut expr_calls_ptr := &expr_calls\n\n\t\tpsi.inspect(file.psi_file.root, fn [mut expr_calls_ptr] (it psi.PsiElement) bool {\n\t\t\tif it is psi.CallExpression {\n\t\t\t\texpr := it.expression() or { return true }\n\t\t\t\ttext := expr.get_text()\n\t\t\t\tif text != 'expr_type' {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\targuments := it.arguments()\n\t\t\t\tif arguments.len != 2 {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\texpr_calls_ptr << it\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t})\n\n\t\tfor call in expr_calls {\n\t\t\targuments := call.arguments()\n\t\t\tif arguments.len != 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfirst := arguments[0]\n\t\t\tsecond := arguments[1]\n\n\t\t\ttyp := psi.infer_type(first)\n\t\t\tgot_type_string := typ.readable_name()\n\n\t\t\tif second is psi.Literal {\n\t\t\t\tfirst_child := second.first_child() or { continue }\n\t\t\t\tif first_child is psi.StringLiteral {\n\t\t\t\t\texpected_type_string := first_child.content()\n\n\t\t\t\t\tif expected_type_string != got_type_string {\n\t\t\t\t\t\tcontaining_file := call.containing_file() or {\n\t\t\t\t\t\t\treturn error('Call expression has no containing file context')\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttest.state = .failed\n\t\t\t\t\t\ttest.message = '\n\t\t\t\t\t\t\t\tIn file ${containing_file.path}:${\n\t\t\t\t\t\t\tcall.text_range().line + 1}\n\n\t\t\t\t\t\t\t\tType mismatch.\n\t\t\t\t\t\t\t\tExpected: ${expected_type_string}\n\t\t\t\t\t\t\t\tFound:    ${got_type_string}\n\n\t\t\t\t\t\t\t'.trim_indent()\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\npub fn (mut t Tester) documentation_test(name string, filepath string) {\n\tmut test := &Test{\n\t\tname: name\n\t}\n\tt.tests << test\n\n\ttest.func = fn [filepath] (mut test Test, mut fixture Fixture) ! {\n\t\tfixture.configure_by_file(filepath) or {\n\t\t\treturn test.fail('Cannot configure fixture: ${err}')\n\t\t}\n\n\t\thover := fixture.documentation_at_cursor() or {\n\t\t\treturn test.fail('Cannot get documentation at cursor')\n\t\t}\n\n\t\tif hover.contents !is lsp.MarkupContent {\n\t\t\treturn test.fail('Documentation is not a MarkupContent')\n\t\t}\n\n\t\tmarkup := hover.contents as lsp.MarkupContent\n\n\t\tif markup.kind != lsp.markup_kind_markdown {\n\t\t\treturn test.fail('Documentation is not a Markdown')\n\t\t}\n\n\t\tmarkdown_filepath := filepath + '.md'\n\t\tmarkdown := os.read_file('testdata/${markdown_filepath}') or {\n\t\t\treturn test.fail('Cannot read expected .md file: ${err}')\n\t\t}\n\n\t\t// if true {\n\t\t// \tos.write_file('testdata/${markdown_filepath}', markup.value) or {}\n\t\t// \treturn\n\t\t// }\n\n\t\ttest.assert_eq(markup.value.trim_right('\\n'), markdown.trim_right('\\n'))!\n\t}\n}\n\npub fn (mut t Tester) scratch_test(name string, test_func fn (mut test Test, mut fixture Fixture) !) {\n\tmut fixture := new_fixture()\n\tfixture.initialize(false) or {\n\t\tprintln('Test failed: ${err}')\n\t\treturn\n\t}\n\n\tmut test := &Test{\n\t\tname: name\n\t}\n\tt.tests << test\n\ttest_func(mut test, mut fixture) or { println('Test failed: ${err}') }\n\n\ttest.print()\n}\n"
  },
  {
    "path": "src/testing/client/TestClient.v",
    "content": "module client\n\nimport jsonrpc\nimport json\nimport io\nimport datatypes\n\n// new_test_client creates a test client to be used for observing responses\n// and notifications from the given handler and interceptors\npub fn new_test_client(handler jsonrpc.Handler, interceptors ...jsonrpc.Interceptor) &TestClient {\n\tmut stream := &TestStream{}\n\tmut server := &jsonrpc.Server{\n\t\thandler:      handler\n\t\tinterceptors: interceptors\n\t\tstream:       stream\n\t}\n\n\treturn &TestClient{\n\t\tserver: server\n\t\tstream: stream\n\t}\n}\n\n// TestResponse is a version of jsonrpc.Response<T> that decodes\n// incoming JSON as raw JSON string.\nstruct TestResponse {\n\traw_id     string @[json: id; raw]\n\traw_result string @[json: result; raw]\n}\n\n// TestClient is a JSONRPC Client used for simulating communication between client and\n// JSONRPC server. This exposes the JSONRPC server and a test stream for sending data\n// as a server or as a client\npub struct TestClient {\nmut:\n\tid int\npub mut:\n\tserver &jsonrpc.Server = unsafe { nil }\n\tstream &TestStream     = unsafe { nil }\n}\n\n// send sends a request and receives a decoded response result.\npub fn (mut tc TestClient) send[T, U](method string, params T) !U {\n\tparams_json := json.encode(params)\n\treq := jsonrpc.Request{\n\t\tid:     '${tc.id}'\n\t\tmethod: method\n\t\tparams: params_json\n\t}\n\n\ttc.stream.send(req)\n\ttc.server.respond() or { return err }\n\traw_json_content := tc.stream.response_text(req.id)\n\tif raw_json_content.len == 0 || raw_json_content == 'null' {\n\t\treturn IError(io.Eof{})\n\t}\n\t// println(raw_json_content)\n\treturn json.decode(U, raw_json_content)!\n}\n\n// notify is a version of send but instead of returning a response,\n// it only notifies the server. Effectively sending a request as a\n// notification.\npub fn (mut tc TestClient) notify[T](method string, params T) ! {\n\tparams_json := json.encode(params)\n\treq := jsonrpc.Request{\n\t\tid:     ''\n\t\tmethod: method\n\t\tparams: params_json\n\t}\n\n\ttc.stream.send(req)\n\ttc.server.respond()!\n}\n\n// TestStream is a io.ReadWriter-compliant stream for sending\n// and receiving responses from between the client and the server.\n// Aside from being a ReaderWriter, it exposes additional methods\n// for decoding JSONRPC response and notifications.\npub struct TestStream {\nmut:\n\tnotif_idx int\n\tnotif_buf [][]u8 = [][]u8{len: 20, cap: 20}\n\tresp_buf  map[string]TestResponse\n\treq_buf   datatypes.Queue[[]u8]\n}\n\n// read receives the incoming request buffer.\npub fn (mut rw TestStream) read(mut buf []u8) !int {\n\treq := rw.req_buf.pop() or { return IError(io.Eof{}) }\n\tbuf << req\n\treturn req.len\n}\n\n// write receives the outgoing response/notification buffer.\npub fn (mut rw TestStream) write(buf []u8) !int {\n\traw_json_content := buf.bytestr().all_after('\\r\\n\\r\\n')\n\tif raw_json_content.contains('\"result\":') {\n\t\tresp := json.decode(TestResponse, raw_json_content) or { return err }\n\t\trw.resp_buf[resp.raw_id] = resp\n\t} else if raw_json_content.contains('\"params\":') {\n\t\tidx := rw.notif_idx % 20\n\t\tfor i := idx + 1; i < rw.notif_buf.len; i++ {\n\t\t\tif rw.notif_buf[i].len != 0 {\n\t\t\t\trw.notif_buf[idx].clear()\n\t\t\t}\n\t\t}\n\t\trw.notif_buf[idx] << buf\n\t\trw.notif_idx++\n\t} else {\n\t\treturn error('none')\n\t}\n\treturn buf.len\n}\n\n// send stringifies and dispatches the jsonrpc.Request into the request queue.\npub fn (mut rw TestStream) send(req jsonrpc.Request) {\n\treq_json := req.json()\n\trw.req_buf.push('Content-Length: ${req_json.len}\\r\\n\\r\\n${req_json}'.bytes())\n}\n\n// response_text returns the raw response result of the given request id.\npub fn (rw &TestStream) response_text(raw_id string) string {\n\treturn rw.resp_buf[raw_id].raw_result\n}\n\n// notification_at returns the jsonrpc.Notification<T> in a given index.\npub fn (rw &TestStream) notification_at[T](idx int) !jsonrpc.NotificationMessage[T] {\n\traw_json_content := rw.notif_buf[idx].bytestr().all_after('\\r\\n\\r\\n')\n\treturn json.decode(jsonrpc.NotificationMessage[T], raw_json_content)!\n}\n\n// last_notification_at_method returns the last jsonrpc.Notification<T> from the given method name.\npub fn (rw &TestStream) last_notification_at_method[T](method_name string) !jsonrpc.NotificationMessage[T] {\n\tfor i := rw.notif_buf.len - 1; i >= 0; i-- {\n\t\traw_notif_content := rw.notif_buf[i]\n\t\tif raw_notif_content.len == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif raw_notif_content.bytestr().contains('\"method\":\"${method_name}\"') {\n\t\t\treturn rw.notification_at[T](i) or { return err }\n\t\t}\n\t}\n\treturn error('')\n}\n\n// RpcResult<T> is a result form used for primitive types.\npub struct RpcResult[T] {\n\tresult T\n}\n"
  },
  {
    "path": "src/tests/analyzer_test.v",
    "content": "module tests\n\nimport os\nimport term\nimport testing\n\nfn test_all() {\n\tdefer {\n\t\tos.rmdir_all(testing.temp_path) or {\n\t\t\tprintln('Failed to remove temp path: ${testing.temp_path}')\n\t\t}\n\t}\n\tos.chdir(os.join_path(@VMODROOT, 'src', 'tests'))!\n\n\tmut testers := []testing.Tester{}\n\n\ttesters << definitions()\n\ttesters << implementations()\n\ttesters << supers()\n\ttesters << completion()\n\ttesters << types()\n\ttesters << documentation()\n\n\trun_only := ''\n\n\tfor mut tester in testers {\n\t\tprintln('Running ${term.bg_blue(' ' + tester.name + ' ')}')\n\t\ttester.run(run_only)\n\t\tprintln('')\n\t\ttester.stats().print()\n\t\tprintln('')\n\t}\n\n\tmut all_stats := testing.TesterStats{}\n\n\tfor tester in testers {\n\t\tall_stats = all_stats.merge(tester.stats())\n\t}\n\n\tprintln(term.bg_blue(' All tests: '))\n\tall_stats.print()\n\n\tif all_stats.failed > 0 {\n\t\tprintln('')\n\t\tprintln(term.bg_red(' Failed tests: '))\n\t\tfor mut tester in testers {\n\t\t\tfor failed_test in tester.failed_tests() {\n\t\t\t\tfailed_test.print()\n\t\t\t}\n\t\t}\n\n\t\texit(1)\n\t}\n}\n"
  },
  {
    "path": "src/tests/bench.v",
    "content": "module tests\n\nimport testing\n\nfn bench() testing.BenchmarkRunner {\n\tmut b := testing.BenchmarkRunner{\n\t\tlast_fixture: unsafe { nil }\n\t}\n\n\tb.bench('inlay hints', fn (mut b testing.Benchmark, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_file('benchmarks/inlay_hints.vv')!\n\n\t\tb.start()\n\n\t\thints := fixture.compute_inlay_hints()\n\t\tprintln('Count: ${hints.len}')\n\n\t\tb.stop()\n\t\tb.print_results()\n\t})\n\n\tb.bench('semantic tokens', fn (mut b testing.Benchmark, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_file('benchmarks/checker.vv')!\n\n\t\tb.start()\n\n\t\ttokens := fixture.compute_semantic_tokens()\n\t\tprintln('Count: ${tokens.data.len / 5}')\n\n\t\tb.stop()\n\t\tb.print_results()\n\t})\n\n\treturn b\n}\n"
  },
  {
    "path": "src/tests/completion.v",
    "content": "module tests\n\nimport testing\nimport server.completion.providers\n\nfn completion() testing.Tester {\n\tmut t := testing.with_name('completion')\n\n\tt.test('struct field completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tstruct SomeFoo {\n\t\t\tname string\n\t\t}\n\n\t\tfn main() {\n\t\t\tfoo := SomeFoo{}\n\t\t\tfoo./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\t\tt.assert_has_only_completion_with_labels(items, 'name', 'str')!\n\t})\n\n\tt.test('struct method completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tstruct Foo {}\n\n\t\tfn (foo Foo) some_method() {\n\t\t}\n\n\t\tfn main() {\n\t\t\tfoo := Foo{}\n\t\t\tfoo./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\t\tt.assert_has_only_completion_with_labels(items, 'some_method', 'str')!\n\t})\n\n\tt.test('variables completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tname := 100\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'name')!\n\t})\n\n\tt.test('assert inside test file', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1_test.v', '\n\t\tfn test_something() {\n\t\t\tasse/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'assert expr')!\n\t\tt.assert_has_completion_with_label(items, 'assert expr, message')!\n\t})\n\n\tt.test('assert as expression', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1_test.v', '\n\t\tfn test_something() {\n\t\t\ta := asse/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_no_completion_with_label(items, 'assert expr')!\n\t\tt.assert_no_completion_with_label(items, 'assert expr, message')!\n\t})\n\n\tt.test('assert outside test file', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn test_something() {\n\t\t\tasse/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_no_completion_with_label(items, 'assert expr')!\n\t\tt.assert_no_completion_with_label(items, 'assert expr, message')!\n\t})\n\n\tt.test('attributes over function', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t[/*caret*/]\n\t\tfn main() {\n\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'direct_array_access')!\n\t\tt.assert_has_completion_with_label(items, \"sql: 'value'\")!\n\t})\n\n\tt.test('json attribute for field', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tstruct Foo {\n\t\t\tsome_value string [js/*caret*/]\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, \"json: 'someValue'\")!\n\t})\n\n\tt.test('json attribute for field with at', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tstruct Foo {\n\t\t\t@enum string [js/*caret*/]\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, \"json: 'enum'\")!\n\t})\n\n\tt.test('json attribute for field with underscore', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tstruct Foo {\n\t\t\ttype_ string [js/*caret*/]\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, \"json: 'type'\")!\n\t})\n\n\tt.test('compile time constant', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t@/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, '@FN')!\n\t\tt.assert_has_completion_with_label(items, '@FILE_LINE')!\n\t})\n\n\tt.test('function like keywords', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'dump()')!\n\t\tt.assert_has_completion_with_label(items, 'sizeof()')!\n\t\tt.assert_has_completion_with_label(items, 'typeof()')!\n\t\tt.assert_has_completion_with_label(items, 'isreftype()')!\n\t\tt.assert_has_completion_with_label(items, '__offsetof()')!\n\t})\n\n\tt.test('inits completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'chan int{}')!\n\t\tt.assert_has_completion_with_label(items, 'map[string]int{}')!\n\t\tt.assert_has_completion_with_label(items, 'thread int{}')!\n\t})\n\n\tt.test('keywords completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'true')!\n\t\tt.assert_has_completion_with_label(items, 'false')!\n\t\tt.assert_has_completion_with_label(items, 'static')!\n\t\tt.assert_has_completion_with_label(items, 'none')!\n\t})\n\n\tt.test('continue and break inside loop', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfor {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'break')!\n\t\tt.assert_has_completion_with_label(items, 'continue')!\n\t})\n\n\tt.test('continue and break outside loop', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_no_completion_with_label(items, 'break')!\n\t\tt.assert_no_completion_with_label(items, 'continue')!\n\t})\n\n\tt.test('module name completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodu/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\t\tif items.len == 0 {\n\t\t\treturn t.fail('no completion variants')\n\t\t}\n\n\t\tt.assert_has_completion_with_label(items, 'module main')!\n\t\tt.assert_has_completion_with_label(items, 'module v_analyzer_test')!\n\t})\n\n\tt.test('module name completion with module clause', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\t\tmodu/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_no_completion_with_label(items, 'module main')!\n\t\tt.assert_no_completion_with_label(items, 'module v_analyzer_test')!\n\t})\n\n\tt.test('nil keyword completion outside unsafe', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'unsafe { nil }')!\n\t})\n\n\tt.test('nil keyword completion inside unsafe', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tunsafe {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'nil')!\n\t})\n\n\tt.test('or block completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfoo() /*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'or { ... }')!\n\t\tt.assert_has_completion_with_label(items, 'or { panic(err) }')!\n\t})\n\n\tt.test('unsafe block completion as expression', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\ta := /*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'unsafe { $0 }')!\n\t})\n\n\tt.test('unsafe block completion as statements', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'unsafe {\\n\\t$0\\n}')!\n\t})\n\n\tt.test('defer block completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'defer { ... }')!\n\t})\n\n\tt.test('return completion inside function without return type', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn foo() {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'return')!\n\t})\n\n\tt.test('return completion inside function with return type', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn foo() int {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'return ')!\n\t})\n\n\tt.test('return completion inside function with bool return type', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn foo() bool {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'return ')!\n\t\tt.assert_has_completion_with_label(items, 'return true')!\n\t\tt.assert_has_completion_with_label(items, 'return false')!\n\t})\n\n\tt.test('top level completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tfor label, _ in providers.top_level_map {\n\t\t\tt.assert_has_completion_with_label(items, label)!\n\t\t\tt.assert_has_completion_with_label(items, 'pub ${label}')!\n\t\t}\n\t})\n\n\tt.test('no top level completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tfor label, _ in providers.top_level_map {\n\t\t\tt.assert_no_completion_with_label(items, label)!\n\t\t\tt.assert_no_completion_with_label(items, 'pub ${label}')!\n\t\t}\n\t})\n\n\tt.test('parameters completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn foo(param_name_1 int, param_name_2 string) {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'param_name_1')!\n\t\tt.assert_has_completion_with_label(items, 'param_name_2')!\n\t})\n\n\tt.test('receiver name completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tstruct Foo {}\n\n\t\tfn (foo_receiver Foo) bar() {\n\t\t\t/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'foo_receiver')!\n\t})\n\n\tt.test('struct as type completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('foo/foo.v', '\n\t\tmodule foo\n\n\t\tpub struct Foo {}\n\t\t'.trim_indent())!\n\n\t\tfixture.configure_by_text('1.v', '\n\t\timport foo\n\n\t\tfn bar() foo./*caret*/ {\n\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'Foo')!\n\t\tt.assert_no_completion_with_insert_text(items, 'Foo{$1}$0')!\n\t})\n\n\tt.test('struct as expression completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('foo/foo.v', '\n\t\tmodule foo\n\n\t\tpub struct Foo {}\n\t\t'.trim_indent())!\n\n\t\tfixture.configure_by_text('1.v', '\n\t\timport foo\n\n\t\tfn bar() {\n\t\t\tfoo./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'Foo{$1}$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'Foo')!\n\t})\n\n\tt.test('imported modules completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\timport arrays\n\t\timport net.http\n\t\timport foo as bar\n\t\timport bar.baz as qux\n\n\t\t/*caret*/\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_label(items, 'arrays')!\n\t\tt.assert_has_completion_with_label(items, 'http')!\n\t\tt.assert_no_completion_with_label(items, 'foo')!\n\t\tt.assert_has_completion_with_label(items, 'bar')!\n\t\tt.assert_no_completion_with_label(items, 'baz')!\n\t\tt.assert_has_completion_with_label(items, 'qux')!\n\t})\n\n\tt.test('function without params completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tfn function_without_params() {}\n\n\t\tfn bar() {\n\t\t\tfunction_without_params/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'function_without_params()$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'function_without_params($1)$0')!\n\t})\n\n\tt.test('function with params completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tfn function_with_params(a int) {}\n\n\t\tfn bar() {\n\t\t\tfunction_with_params/*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'function_with_params($1)$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'function_with_params()$0')!\n\t})\n\n\tt.test('static method completion', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tstruct TestStruct {}\n\n\t\tfn TestStruct.static_method() {}\n\n\t\tfn main() {\n\t\t\tTestStruct./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'static_method()$0')!\n\t})\n\n\tt.test('enum methods', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tenum Colors {\n\t\t\tred\n\t\t\tgreen\n\t\t}\n\n\t\tfn (c Colors) some_method() {}\n\n\t\tfn main() {\n\t\t\tc := Colors.red\n\t\t\tc./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'red')!\n\t\tt.assert_has_completion_with_insert_text(items, 'green')!\n\t\tt.assert_has_completion_with_insert_text(items, 'some_method()$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'all($1)$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'has($1)$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'clear($1)$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'set($1)$0')!\n\t\tt.assert_no_completion_with_insert_text(items, 'toggle($1)$0')!\n\t})\n\n\tt.test('enum flag methods', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\t[flag]\n\t\tenum Colors {\n\t\t\tred\n\t\t\tgreen\n\t\t}\n\n\t\tfn main() {\n\t\t\tc := Colors.red\n\t\t\tc./*caret*/\n\t\t}\n\t\t'.trim_indent())!\n\n\t\titems := fixture.complete_at_cursor()\n\n\t\tt.assert_has_completion_with_insert_text(items, 'red')!\n\t\tt.assert_has_completion_with_insert_text(items, 'green')!\n\t\tt.assert_has_completion_with_insert_text(items, 'all($1)$0')!\n\t\tt.assert_has_completion_with_insert_text(items, 'has($1)$0')!\n\t\tt.assert_has_completion_with_insert_text(items, 'clear($1)$0')!\n\t\tt.assert_has_completion_with_insert_text(items, 'set($1)$0')!\n\t\tt.assert_has_completion_with_insert_text(items, 'toggle($1)$0')!\n\t})\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tests/definitions.v",
    "content": "module tests\n\nimport testing\n\nfn definitions() testing.Tester {\n\tmut t := testing.with_name('definitions')\n\n\tt.test('simple variable definition', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tname := 100\n\t\t\tprintln(na/*caret*/me)\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'name')!\n\t})\n\n\tt.test('variable definition from outer scope', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tname := 100\n\t\t\tif true {\n\t\t\t\tprintln(na/*caret*/me)\n\t\t\t}\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'name')!\n\t})\n\n\tt.test('variable definition from outer scope after inner scope', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tif true {\n\t\t\t\tprintln(so/*caret*/me_variable)\n\t\t\t}\n\t\t\tsome_variable := 100\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_no_definition(locations)!\n\t})\n\n\tt.test('variable definition from for loop', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tfor index := 0; index < 100; index++ {\n\t\t\t\tprintln(inde/*caret*/x)\n\t\t\t}\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'index')!\n\t})\n\n\tt.test('variable definition from for in loop', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tfor index in 0 .. 100 {\n\t\t\t\tprintln(inde/*caret*/x)\n\t\t\t}\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'index')!\n\t})\n\n\tt.test('variable definition from if unwrapping', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tif value := foo() {\n\t\t\t\tprintln(val/*caret*/ue)\n\t\t\t}\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'value')!\n\t})\n\n\t// TODO: This probably should be prohibited\n\tt.test('variable definition from if unwrapping in else', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tif value := foo() {\n\n\t\t\t} else {\n\t\t\t\tprintln(val/*caret*/ue)\n\t\t\t}\n \t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'value')!\n\t})\n\n\tt.test('variable definition from if unwrapping from outside', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tfn main() {\n\t\t\tif some_variable := foo() {}\n\n\t\t\tprintln(some/*caret*/_variable)\n \t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_no_definition(locations)!\n\t})\n\n\tt.test('field definition', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tstruct FooStruct {\n\t\t\tname string\n\t\t}\n\n\t\tfn main() {\n\t\t\tfoo := FooStruct{}\n\t\t\tprintln(foo.na/*caret*/me)\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'name')!\n\t})\n\n\tt.test('method definition', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tstruct Foo {\n\t\t\tname string\n\t\t}\n\n\t\tfn (foo Foo) get_name() string {\n\t\t\treturn foo.name\n\t\t}\n\n\t\tfn main() {\n\t\t\tfoo := Foo{}\n\t\t\tprintln(foo.get_na/*caret*/me())\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'get_name')!\n\t})\n\n\tt.test('top level variable', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tname := 100\n\t\tprintln(na/*caret*/me)\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'name')!\n\t})\n\n\tt.test('top level variable from outer scope', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tname := 100\n\t\tif true {\n\t\t\tprintln(na/*caret*/me)\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'name')!\n\t})\n\n\tt.test('it as function parameter', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', \"\n\t\tfn foo(it int) {\n\t\t\tif i/*caret*/t.str() == 1 {\n\t\t\t\tprintln('one')\n\t\t\t}\n\t\t}\n\t\t\".trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'it')!\n\t})\n\n\tt.slow_test('shell script implicit os module', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tabs_/*caret*/path()\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri_from_stdlib(first.target_uri, 'filepath.v')!\n\t})\n\n\tt.test('shell script implicit os module constant', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\t\tar/*caret*/gs\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri_from_stdlib(first.target_uri, 'os.c.v')!\n\t})\n\n\tt.slow_test('shell script local function', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tfn some_fn() {}\n\n\t\t/*caret*/some_fn()\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'some_fn')!\n\t})\n\n\tt.slow_test('shell script local constant', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tconst some_constant = 100\n\n\t\t/*caret*/some_constant\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'some_constant')!\n\t})\n\n\tt.test('static methods', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tmodule main\n\n\t\tstruct TestStruct {}\n\n\t\tfn TestStruct.static_method() {}\n\n\t\tfn main() {\n\t\t\tTestStruct.static/*caret*/_method()\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'static_method')!\n\t})\n\n\tt.test('enum inside special flag field method call', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tmodule main\n\n\t\t[flag]\n\t\tenum Colors {\n\t\t\tred\n\t\t\tgreen\n\t\t}\n\n\t\tfn main() {\n\t\t\tmut color := Colors.green\n\t\t\tcolor.has(.r/*caret*/ed)\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'red')!\n\t})\n\n\tt.test('enum fields or', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tmodule main\n\n\t\t[flag]\n\t\tenum Colors {\n\t\t\tred\n\t\t\tgreen\n\t\t}\n\n\t\tfn main() {\n\t\t\tmut color := Colors.green | .r/*caret*/ed\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'red')!\n\t})\n\n\tt.test('implicit str method', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.vsh', '\n\t\tmodule main\n\n\t\tstruct Foo {}\n\n\t\tfn main() {\n\t\t\tmut foo := Foo{}\n\t\t\tfoo.s/*caret*/tr()\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri_from_stubs(first.target_uri, 'implicit.v')!\n\t})\n\n\tt.test('global variable with volatile modifier', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n        __global volatile base_revision = 0\n\n        fn main() {\n            println(base/*caret*/_revision)\n        }\n        '.trim_indent())!\n\n\t\tlocations := fixture.definition_at_cursor()\n\t\tt.assert_has_definition(locations)!\n\n\t\tfirst := locations.first()\n\t\tt.assert_uri(first.target_uri, fixture.current_file_uri())!\n\t\tt.assert_definition_name(first, 'base_revision')!\n\t})\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tests/documentation.v",
    "content": "module tests\n\nimport testing\n\nfn documentation() testing.Tester {\n\tmut t := testing.with_name('documentation')\n\n\tt.documentation_test('rendered', 'documentation/rendered.vv')\n\tt.documentation_test('stubs', 'documentation/stubs.vv')\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tests/implementations.v",
    "content": "module tests\n\nimport testing\n\nfn implementations() testing.Tester {\n\tmut t := testing.with_name('implementations')\n\n\tt.test('method interface implementation', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo()\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_has_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method interface implementation with return type', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo() string\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) foo() string {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_has_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method interface implementation with parameters', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo(age int, name string) string\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) foo(age int, name string) string {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_has_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method interface implementation with parameters, parameters types mismatch', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo(age int, name ?string) string\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) foo(age int, name string) string {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_no_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method interface implementation with fields', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo string\n\t\t}\n\n\t\tstruct FooImpl {\n\t\t\tfoo string\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_has_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method interface implementation with fields, types mismatch', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface /*caret*/IFoo {\n\t\t\tfoo ?string\n\t\t}\n\n\t\tstruct FooImpl {\n\t\t\tfoo string\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_no_implementation_with_name(locations, 'FooImpl')!\n\t})\n\n\tt.test('method implementation', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\t/*caret*/foo()\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.implementation_at_cursor()\n\t\tt.assert_has_implementation_with_name(locations, 'foo')!\n\t})\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tests/supers.v",
    "content": "module tests\n\nimport testing\n\nfn supers() testing.Tester {\n\tmut t := testing.with_name('supers')\n\n\tt.test('super interface with method', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\tfoo()\n\t\t}\n\n\t\tstruct /*caret*/FooImpl {}\n\n\t\tfn (f FooImpl) foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.supers_at_cursor()\n\t\tt.assert_has_super_with_name(locations, 'IFoo')!\n\t})\n\n\tt.test('super interface with field', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\tfoo string\n\t\t}\n\n\t\tstruct /*caret*/FooImpl {\n\t\t\tfoo string\n\t\t}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.supers_at_cursor()\n\t\tt.assert_has_super_with_name(locations, 'IFoo')!\n\t})\n\n\tt.test('super interface with method and field', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\tfield string\n\t\t\tfoo()\n\t\t}\n\n\t\tstruct /*caret*/FooImpl {\n\t\t\tfield string\n\t\t}\n\n\t\tfn (f FooImpl) foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.supers_at_cursor()\n\t\tt.assert_has_super_with_name(locations, 'IFoo')!\n\t})\n\n\tt.test('super interface with method and field with mismatched type', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\tfield string\n\t\t\tfoo()\n\t\t}\n\n\t\tstruct /*caret*/FooImpl {\n\t\t\tfield int\n\t\t}\n\n\t\tfn (f FooImpl) foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.supers_at_cursor()\n\t\tt.assert_no_super_with_name(locations, 'IFoo')!\n\t})\n\n\tt.test('super method', fn (mut t testing.Test, mut fixture testing.Fixture) ! {\n\t\tfixture.configure_by_text('1.v', '\n\t\tmodule main\n\n\t\tinterface IFoo {\n\t\t\tfoo()\n\t\t}\n\n\t\tstruct FooImpl {}\n\n\t\tfn (f FooImpl) /*caret*/foo() {}\n\t\t'.trim_indent())!\n\n\t\tlocations := fixture.supers_at_cursor()\n\t\tt.assert_has_super_with_name(locations, 'foo')!\n\t})\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tests/testdata/benchmarks/checker.vv",
    "content": "// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.\n// Use of this source code is governed by an MIT license that can be found in the LICENSE file.\nmodule checker\n\nimport os\nimport strconv\nimport v.ast\nimport v.vmod\nimport v.token\nimport v.pref\nimport v.util\nimport v.util.version\nimport v.errors\nimport v.pkgconfig\nimport v.transformer\nimport v.comptime\n\nconst int_min = int(0x80000000)\nconst int_max = int(0x7FFFFFFF)\n// prevent stack overflows by restricting too deep recursion:\nconst expr_level_cutoff_limit = 40\nconst stmt_level_cutoff_limit = 40\nconst iface_level_cutoff_limit = 100\nconst generic_fn_cutoff_limit_per_fn = 10_000 // how many times post_process_generic_fns, can visit the same function before bailing out\n\nconst generic_fn_postprocess_iterations_cutoff_limit = 1000_000\n\n// array_builtin_methods contains a list of all methods on array, that return other typed arrays,\n// i.e. that act as *pseudogeneric* methods, that need compiler support, so that the types of the results\n// are properly checked.\n// Note that methods that do not return anything, or that return known types, are not listed here, since they are just ordinary non generic methods.\npub const array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map', 'slice', 'sort',\n\t'sorted', 'sorted_with_compare', 'contains', 'index', 'wait', 'any', 'all', 'first', 'last',\n\t'pop', 'delete']\npub const array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(array_builtin_methods)\n// TODO: remove `byte` from this list when it is no longer supported\npub const reserved_type_names = ['byte', 'bool', 'char', 'i8', 'i16', 'int', 'i64', 'u8', 'u16',\n\t'u32', 'u64', 'f32', 'f64', 'map', 'string', 'rune', 'usize', 'isize', 'voidptr', 'thread']\npub const reserved_type_names_chk = token.new_keywords_matcher_from_array_trie(reserved_type_names)\npub const vroot_is_deprecated_message = '@VROOT is deprecated, use @VMODROOT or @VEXEROOT instead'\n\n@[heap; minify]\npub struct Checker {\npub mut:\n\tpref &pref.Preferences = unsafe { nil } // Preferences shared from V struct\n\t//\n\ttable &ast.Table = unsafe { nil }\n\tfile  &ast.File  = unsafe { nil }\n\t//\n\tnr_errors     int\n\tnr_warnings   int\n\tnr_notices    int\n\terrors        []errors.Error\n\twarnings      []errors.Warning\n\tnotices       []errors.Notice\n\terror_lines   map[string]bool // dedup errors\n\twarning_lines map[string]bool // dedup warns\n\tnotice_lines  map[string]bool // dedup notices\n\terror_details []string\n\tshould_abort  bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time.\n\t//\n\texpected_type              ast.Type\n\texpected_or_type           ast.Type        // fn() or { 'this type' } eg. string. expected or block type\n\texpected_expr_type         ast.Type        // if/match is_expr: expected_type\n\tmod                        string          // current module name\n\tconst_var                  &ast.ConstField = unsafe { nil } // the current constant, when checking const declarations\n\tconst_deps                 []string\n\tconst_names                []string\n\tglobal_names               []string\n\tlocked_names               []string // vars that are currently locked\n\trlocked_names              []string // vars that are currently read-locked\n\tin_for_count               int      // if checker is currently in a for loop\n\treturns                    bool\n\tscope_returns              bool\n\tis_builtin_mod             bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this\n\tis_just_builtin_mod        bool // true only inside 'builtin'\n\tis_generated               bool // true for `[generated] module xyz` .v files\n\tinside_unsafe              bool // true inside `unsafe {}` blocks\n\tinside_const               bool // true inside `const ( ... )` blocks\n\tinside_anon_fn             bool // true inside `fn() { ... }()`\n\tinside_lambda              bool // true inside `|...| ...`\n\tinside_ref_lit             bool // true inside `a := &something`\n\tinside_defer               bool // true inside `defer {}` blocks\n\tinside_return              bool // true inside `return ...` blocks\n\tinside_fn_arg              bool // `a`, `b` in `a.f(b)`\n\tinside_ct_attr             bool // true inside `[if expr]`\n\tinside_x_is_type           bool // true inside the Type expression of `if x is Type {`\n\tinside_generic_struct_init bool\n\tcur_struct_generic_types   []ast.Type\n\tcur_struct_concrete_types  []ast.Type\n\tskip_flags                 bool      // should `#flag` and `#include` be skipped\n\tfn_level                   int       // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc\n\tsmartcast_mut_pos          token.Pos // match mut foo, if mut foo is Foo\n\tsmartcast_cond_pos         token.Pos // match cond\n\tct_cond_stack              []ast.Expr\n\tct_user_defines            map[string]ComptimeBranchSkipState\n\tct_system_defines          map[string]ComptimeBranchSkipState\nmut:\n\tstmt_level int // the nesting level inside each stmts list;\n\t// .stmt_level is used to check for `evaluated but not used` ExprStmts like `1 << 1`\n\t// 1 for statements directly at each inner scope level;\n\t// increases for `x := if cond { statement_list1} else {statement_list2}`;\n\t// increases for `x := optfn() or { statement_list3 }`;\n\t// files                            []ast.File\n\texpr_level                       int // to avoid infinite recursion segfaults due to compiler bugs\n\tensure_generic_type_level        int // to avoid infinite recursion segfaults in ensure_generic_type_specify_type_names\n\tcur_orm_ts                       ast.TypeSymbol\n\tcur_anon_fn                      &ast.AnonFn = unsafe { nil }\n\tvmod_file_content                string     // needed for @VMOD_FILE, contents of the file, *NOT its path**\n\tloop_label                       string     // set when inside a labelled for loop\n\tvweb_gen_types                   []ast.Type // vweb route checks\n\ttimers                           &util.Timers = util.get_timers()\n\tcomptime_info_stack              []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier\n\tcomptime                         comptime.ComptimeInfo\n\tfn_scope                         &ast.Scope = unsafe { nil }\n\tmain_fn_decl_node                ast.FnDecl\n\tmatch_exhaustive_cutoff_limit    int = 10\n\tis_last_stmt                     bool\n\tprevent_sum_type_unwrapping_once bool // needed for assign new values to sum type, stopping unwrapping then\n\tusing_new_err_struct             bool\n\tneed_recheck_generic_fns         bool // need recheck generic fns because there are cascaded nested generic fn\n\tinside_sql                       bool // to handle sql table fields pseudo variables\n\tinside_selector_expr             bool\n\tinside_interface_deref           bool\n\tinside_decl_rhs                  bool\n\tinside_if_guard                  bool // true inside the guard condition of `if x := opt() {}`\n\tinside_assign                    bool\n\t// doing_line_info                  int    // a quick single file run when called with v -line-info (contains line nr to inspect)\n\t// doing_line_path                  string // same, but stores the path being parsed\n\tis_index_assign   bool\n\tcomptime_call_pos int // needed for correctly checking use before decl for templates\n\tgoto_labels       map[string]ast.GotoLabel // to check for unused goto labels\n\tenum_data_type    ast.Type\n\tfield_data_type   ast.Type\n\tvariant_data_type ast.Type\n\tfn_return_type    ast.Type\n\torm_table_fields  map[string][]ast.StructField // known table structs\n\t//\n\tv_current_commit_hash string // same as old C.V_CURRENT_COMMIT_HASH\n}\n\npub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker {\n\tmut timers_should_print := false\n\t$if time_checking ? {\n\t\ttimers_should_print = true\n\t}\n\tmut checker := &Checker{\n\t\ttable: table\n\t\tpref: pref_\n\t\ttimers: util.new_timers(should_print: timers_should_print, label: 'checker')\n\t\tmatch_exhaustive_cutoff_limit: pref_.checker_match_exhaustive_cutoff_limit\n\t\tv_current_commit_hash: version.githash(pref_.building_v)\n\t}\n\tchecker.comptime = &comptime.ComptimeInfo{\n\t\tresolver: checker\n\t\ttable: table\n\t}\n\treturn checker\n}\n\nfn (mut c Checker) reset_checker_state_at_start_of_new_file() {\n\tc.expected_type = ast.void_type\n\tc.expected_or_type = ast.void_type\n\tc.const_var = unsafe { nil }\n\tc.in_for_count = 0\n\tc.returns = false\n\tc.scope_returns = false\n\tc.mod = ''\n\tc.is_builtin_mod = false\n\tc.is_just_builtin_mod = false\n\tc.inside_unsafe = false\n\tc.inside_const = false\n\tc.inside_anon_fn = false\n\tc.inside_ref_lit = false\n\tc.inside_defer = false\n\tc.inside_fn_arg = false\n\tc.inside_ct_attr = false\n\tc.inside_x_is_type = false\n\tc.skip_flags = false\n\tc.fn_level = 0\n\tc.expr_level = 0\n\tc.stmt_level = 0\n\tc.inside_sql = false\n\tc.cur_orm_ts = ast.TypeSymbol{}\n\tc.prevent_sum_type_unwrapping_once = false\n\tc.loop_label = ''\n\tc.using_new_err_struct = false\n\tc.inside_selector_expr = false\n\tc.inside_interface_deref = false\n\tc.inside_decl_rhs = false\n\tc.inside_if_guard = false\n\tc.error_details.clear()\n}\n\npub fn (mut c Checker) check(mut ast_file ast.File) {\n\tc.reset_checker_state_at_start_of_new_file()\n\tc.change_current_file(ast_file)\n\tfor i, ast_import in ast_file.imports {\n\t\t// Imports with the same path and name (self-imports and module name conflicts with builtin module imports)\n\t\tif c.mod == ast_import.mod {\n\t\t\tc.error('cannot import `${ast_import.mod}` into a module with the same name',\n\t\t\t\tast_import.mod_pos)\n\t\t}\n\t\t// Duplicates of regular imports with the default alias (modname) and `as` imports with a custom alias\n\t\tif c.mod == ast_import.alias {\n\t\t\tif c.mod == ast_import.mod.all_after_last('.') {\n\t\t\t\tc.error('cannot import `${ast_import.mod}` into a module with the same name',\n\t\t\t\t\tast_import.mod_pos)\n\t\t\t}\n\t\t\tc.error('cannot import `${ast_import.mod}` as `${ast_import.alias}` into a module with the same name',\n\t\t\t\tast_import.alias_pos)\n\t\t}\n\t\tfor sym in ast_import.syms {\n\t\t\tfull_name := ast_import.mod + '.' + sym.name\n\t\t\tif full_name in c.const_names {\n\t\t\t\tc.error('cannot selectively import constant `${sym.name}` from `${ast_import.mod}`, import `${ast_import.mod}` and use `${full_name}` instead',\n\t\t\t\t\tsym.pos)\n\t\t\t}\n\t\t}\n\t\tfor j in 0 .. i {\n\t\t\tif ast_import.mod == ast_file.imports[j].mod {\n\t\t\t\tc.error('`${ast_import.mod}` was already imported on line ${\n\t\t\t\t\tast_file.imports[j].mod_pos.line_nr + 1}', ast_import.mod_pos)\n\t\t\t} else if ast_import.mod == ast_file.imports[j].alias {\n\t\t\t\tc.error('`${ast_file.imports[j].mod}` was already imported as `${ast_import.alias}` on line ${\n\t\t\t\t\tast_file.imports[j].mod_pos.line_nr + 1}', ast_import.mod_pos)\n\t\t\t} else if ast_import.alias != '_' && ast_import.alias == ast_file.imports[j].alias {\n\t\t\t\tc.error('`${ast_file.imports[j].mod}` was already imported on line ${\n\t\t\t\t\tast_file.imports[j].alias_pos.line_nr + 1}', ast_import.alias_pos)\n\t\t\t}\n\t\t}\n\t}\n\tc.stmt_level = 0\n\tfor mut stmt in ast_file.stmts {\n\t\tif stmt in [ast.ConstDecl, ast.ExprStmt] {\n\t\t\tc.expr_level = 0\n\t\t\tc.stmt(mut stmt)\n\t\t}\n\t\tif c.should_abort {\n\t\t\treturn\n\t\t}\n\t}\n\n\tc.stmt_level = 0\n\tfor mut stmt in ast_file.stmts {\n\t\tif stmt is ast.GlobalDecl {\n\t\t\tc.expr_level = 0\n\t\t\tc.stmt(mut stmt)\n\t\t}\n\t\tif c.should_abort {\n\t\t\treturn\n\t\t}\n\t}\n\n\tc.stmt_level = 0\n\tfor mut stmt in ast_file.stmts {\n\t\tif stmt !in [ast.ConstDecl, ast.GlobalDecl, ast.ExprStmt] {\n\t\t\tc.expr_level = 0\n\t\t\tc.stmt(mut stmt)\n\t\t}\n\t\tif c.should_abort {\n\t\t\treturn\n\t\t}\n\t}\n\n\tc.check_scope_vars(c.file.scope)\n\tc.check_unused_labels()\n}\n\npub fn (mut c Checker) check_scope_vars(sc &ast.Scope) {\n\tif !c.pref.is_repl && !c.file.is_test {\n\t\tfor _, obj in sc.objects {\n\t\t\tmatch obj {\n\t\t\t\tast.Var {\n\t\t\t\t\tif !obj.is_used && obj.name[0] != `_` {\n\t\t\t\t\t\tif !c.pref.translated && !c.file.is_translated {\n\t\t\t\t\t\t\tc.warn('unused variable: `${obj.name}`', obj.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif obj.is_mut && !obj.is_changed && !c.is_builtin_mod && obj.name != 'it' {\n\t\t\t\t\t\t// if obj.is_mut && !obj.is_changed && !c.is_builtin {  //TODO C error bad field not checked\n\t\t\t\t\t\t// c.warn('`$obj.name` is declared as mutable, but it was never changed',\n\t\t\t\t\t\t// obj.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t}\n\tfor child in sc.children {\n\t\tc.check_scope_vars(child)\n\t}\n}\n\n// not used right now\npub fn (mut c Checker) check2(mut ast_file ast.File) []errors.Error {\n\tc.change_current_file(ast_file)\n\tfor mut stmt in ast_file.stmts {\n\t\tc.stmt(mut stmt)\n\t}\n\treturn c.errors\n}\n\npub fn (mut c Checker) change_current_file(file &ast.File) {\n\tc.file = unsafe { file }\n\tc.vmod_file_content = ''\n\tc.mod = file.mod.name\n\tc.is_generated = file.is_generated\n}\n\npub fn (mut c Checker) check_files(ast_files []&ast.File) {\n\t// println('check_files')\n\t// c.files = ast_files\n\tmut has_main_mod_file := false\n\tmut has_main_fn := false\n\tunsafe {\n\t\tmut files_from_main_module := []&ast.File{}\n\t\tfor i in 0 .. ast_files.len {\n\t\t\tmut file := ast_files[i]\n\t\t\tc.timers.start('checker_check ${file.path}')\n\t\t\tc.check(mut file)\n\t\t\tif file.mod.name == 'main' {\n\t\t\t\tfiles_from_main_module << file\n\t\t\t\thas_main_mod_file = true\n\t\t\t\tif c.file_has_main_fn(file) {\n\t\t\t\t\thas_main_fn = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.timers.show('checker_check ${file.path}')\n\t\t}\n\t\tif has_main_mod_file && !has_main_fn && files_from_main_module.len > 0 {\n\t\t\tif c.pref.is_script && !c.pref.is_test {\n\t\t\t\t// files_from_main_module contain preludes at the start\n\t\t\t\tmut the_main_file := files_from_main_module.last()\n\t\t\t\tthe_main_file.stmts << ast.FnDecl{\n\t\t\t\t\tname: 'main.main'\n\t\t\t\t\tmod: 'main'\n\t\t\t\t\tis_main: true\n\t\t\t\t\tfile: the_main_file.path\n\t\t\t\t\treturn_type: ast.void_type\n\t\t\t\t\tscope: &ast.Scope{\n\t\t\t\t\t\tparent: nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thas_main_fn = true\n\t\t\t}\n\t\t}\n\t}\n\tc.timers.start('checker_post_process_generic_fns')\n\tlast_file := c.file\n\t// post process generic functions. must be done after all files have been\n\t// checked, to ensure all generic calls are processed, as this information\n\t// is needed when the generic type is auto inferred from the call argument.\n\t// we may have to loop several times, if there were more concrete types found.\n\tmut post_process_generic_fns_iterations := 0\n\tpost_process_iterations_loop: for post_process_generic_fns_iterations <= checker.generic_fn_postprocess_iterations_cutoff_limit {\n\t\t$if trace_post_process_generic_fns_loop ? {\n\t\t\teprintln('>>>>>>>>> recheck_generic_fns loop iteration: ${post_process_generic_fns_iterations}')\n\t\t}\n\t\tfor file in ast_files {\n\t\t\tif file.generic_fns.len > 0 {\n\t\t\t\t$if trace_post_process_generic_fns_loop ? {\n\t\t\t\t\teprintln('>> file.path: ${file.path:-40} | file.generic_fns:' +\n\t\t\t\t\t\tfile.generic_fns.map(it.name).str())\n\t\t\t\t}\n\t\t\t\tc.change_current_file(file)\n\t\t\t\tc.post_process_generic_fns() or { break post_process_iterations_loop }\n\t\t\t}\n\t\t}\n\t\tif !c.need_recheck_generic_fns {\n\t\t\tbreak\n\t\t}\n\t\tc.need_recheck_generic_fns = false\n\t\tpost_process_generic_fns_iterations++\n\t}\n\t$if trace_post_process_generic_fns_loop ? {\n\t\teprintln('>>>>>>>>> recheck_generic_fns loop done, iteration: ${post_process_generic_fns_iterations}')\n\t}\n\t// restore the original c.file && c.mod after post processing\n\tc.change_current_file(last_file)\n\tc.timers.show('checker_post_process_generic_fns')\n\n\tc.timers.start('checker_verify_all_vweb_routes')\n\tc.verify_all_vweb_routes()\n\tc.timers.show('checker_verify_all_vweb_routes')\n\n\tif c.pref.is_test {\n\t\tmut n_test_fns := 0\n\t\tfor _, f in c.table.fns {\n\t\t\tif f.is_test {\n\t\t\t\tn_test_fns++\n\t\t\t}\n\t\t}\n\t\tif n_test_fns == 0 {\n\t\t\tc.add_error_detail('The name of a test function in V, should start with `test_`.')\n\t\t\tc.add_error_detail('The test function should take 0 parameters, and no return type. Example:')\n\t\t\tc.add_error_detail('fn test_xyz(){ assert 2 + 2 == 4 }')\n\t\t\tc.error('a _test.v file should have *at least* one `test_` function', token.Pos{})\n\t\t}\n\t}\n\t// After the main checker run, run the line info check, print line info, and exit (if it's present)\n\tif !c.pref.linfo.is_running && c.pref.line_info != '' { //'' && c.pref.linfo.line_nr == 0 {\n\t\t// c.do_line_info(c.pref.line_info, ast_files)\n\t\tprintln('setting is_running=true,  pref.path=${c.pref.linfo.path} curdir' + os.getwd())\n\t\tc.pref.linfo.is_running = true\n\t\tfor i, file in ast_files {\n\t\t\t// println(file.path)\n\t\t\tif file.path == c.pref.linfo.path {\n\t\t\t\tprintln('running c.check_files')\n\t\t\t\tc.check_files([ast_files[i]])\n\t\t\t\texit(0)\n\t\t\t} else if file.path.starts_with('./') {\n\t\t\t\t// Maybe it's a \"./foo.v\", linfo.path has an absolute path\n\t\t\t\tabs_path := os.join_path(os.getwd(), file.path).replace('/./', '/') // TODO join_path shouldn't have /./\n\t\t\t\tif abs_path == c.pref.linfo.path {\n\t\t\t\t\tc.check_files([ast_files[i]])\n\t\t\t\t\texit(0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintln('failed to find file \"${c.pref.linfo.path}\"')\n\t\texit(0)\n\t}\n\t// Make sure fn main is defined in non lib builds\n\tif c.pref.build_mode == .build_module || c.pref.is_test {\n\t\treturn\n\t}\n\tif c.pref.is_shared {\n\t\t// shared libs do not need to have a main\n\t\treturn\n\t}\n\tif c.pref.no_builtin {\n\t\t// `v -no-builtin module/` do not necessarily need to have a `main` function\n\t\t// This is useful for compiling linux kernel modules for example.\n\t\treturn\n\t}\n\tif !has_main_mod_file {\n\t\tc.error('project must include a `main` module or be a shared library (compile with `v -shared`)',\n\t\t\ttoken.Pos{})\n\t} else if !has_main_fn && !c.pref.is_o {\n\t\tc.error('function `main` must be declared in the main module', token.Pos{})\n\t}\n}\n\n// do checks specific to files in main module\n// returns `true` if a main function is in the file\nfn (mut c Checker) file_has_main_fn(file &ast.File) bool {\n\tmut has_main_fn := false\n\tfor stmt in file.stmts {\n\t\tif stmt is ast.FnDecl {\n\t\t\tif stmt.name == 'main.main' {\n\t\t\t\tif has_main_fn {\n\t\t\t\t\tc.error('function `main` is already defined', stmt.pos)\n\t\t\t\t}\n\t\t\t\thas_main_fn = true\n\t\t\t\tif stmt.params.len > 0 {\n\t\t\t\t\tc.error('function `main` cannot have arguments', stmt.pos)\n\t\t\t\t}\n\t\t\t\tif stmt.return_type != ast.void_type {\n\t\t\t\t\tc.error('function `main` cannot return values', stmt.pos)\n\t\t\t\t}\n\t\t\t\tif stmt.no_body {\n\t\t\t\t\tc.error('function `main` must declare a body', stmt.pos)\n\t\t\t\t}\n\t\t\t} else if stmt.attrs.contains('console') {\n\t\t\t\tc.error('only `main` can have the `[console]` attribute', stmt.pos)\n\t\t\t}\n\t\t}\n\t}\n\treturn has_main_fn\n}\n\nfn (mut c Checker) check_valid_snake_case(name string, identifier string, pos token.Pos) {\n\tif c.pref.translated || c.file.is_translated {\n\t\treturn\n\t}\n\tif !c.pref.is_vweb && name.len > 1 && (name[0] == `_` || name.contains('._')) {\n\t\tc.error('${identifier} `${name}` cannot start with `_`', pos)\n\t}\n\tif !c.pref.experimental && util.contains_capital(name) {\n\t\tc.error('${identifier} `${name}` cannot contain uppercase letters, use snake_case instead',\n\t\t\tpos)\n\t}\n}\n\nfn stripped_name(name string) string {\n\tidx := name.last_index('.') or { -1 }\n\treturn name[(idx + 1)..]\n}\n\nfn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos token.Pos) {\n\tif c.pref.translated || c.file.is_translated {\n\t\treturn\n\t}\n\tsname := stripped_name(name)\n\tif sname.len > 0 && !sname[0].is_capital() {\n\t\tc.error('${identifier} `${name}` must begin with capital letter', pos)\n\t}\n}\n\nfn (mut c Checker) type_decl(node ast.TypeDecl) {\n\tmatch node {\n\t\tast.AliasTypeDecl { c.alias_type_decl(node) }\n\t\tast.FnTypeDecl { c.fn_type_decl(node) }\n\t\tast.SumTypeDecl { c.sum_type_decl(node) }\n\t}\n}\n\nfn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {\n\tif c.file.mod.name != 'builtin' && !node.name.starts_with('C.') {\n\t\tc.check_valid_pascal_case(node.name, 'type alias', node.pos)\n\t}\n\tif !c.ensure_type_exists(node.parent_type, node.type_pos) {\n\t\treturn\n\t}\n\tmut parent_typ_sym := c.table.sym(node.parent_type)\n\tif node.parent_type.has_flag(.result) {\n\t\tc.add_error_detail('Result types cannot be stored and have to be unwrapped immediately')\n\t\tc.error('cannot make an alias of Result type', node.type_pos)\n\t}\n\tmatch parent_typ_sym.kind {\n\t\t.placeholder, .int_literal, .float_literal {\n\t\t\tc.error('unknown aliased type `${parent_typ_sym.name}`', node.type_pos)\n\t\t}\n\t\t.alias {\n\t\t\torig_sym := c.table.sym((parent_typ_sym.info as ast.Alias).parent_type)\n\t\t\tc.error('type `${parent_typ_sym.str()}` is an alias, use the original alias type `${orig_sym.name}` instead',\n\t\t\t\tnode.type_pos)\n\t\t}\n\t\t.chan {\n\t\t\tc.error('aliases of `chan` types are not allowed', node.type_pos)\n\t\t}\n\t\t.thread {\n\t\t\tc.error('aliases of `thread` types are not allowed', node.type_pos)\n\t\t}\n\t\t.multi_return {\n\t\t\tc.error('aliases of function multi return types are not allowed', node.type_pos)\n\t\t}\n\t\t.void {\n\t\t\tc.error('aliases of the void type are not allowed', node.type_pos)\n\t\t}\n\t\t.function {\n\t\t\torig_sym := c.table.type_to_str(node.parent_type)\n\t\t\tc.error('type `${parent_typ_sym.str()}` is an alias, use the original alias type `${orig_sym}` instead',\n\t\t\t\tnode.type_pos)\n\t\t}\n\t\t.struct_ {\n\t\t\tif mut parent_typ_sym.info is ast.Struct {\n\t\t\t\t// check if the generic param types have been defined\n\t\t\t\tfor ct in parent_typ_sym.info.concrete_types {\n\t\t\t\t\tct_sym := c.table.sym(ct)\n\t\t\t\t\tif ct_sym.kind == .placeholder {\n\t\t\t\t\t\tc.error('unknown type `${ct_sym.name}`', node.type_pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.array {\n\t\t\tc.check_alias_vs_element_type_of_parent(node, (parent_typ_sym.info as ast.Array).elem_type,\n\t\t\t\t'array')\n\t\t}\n\t\t.array_fixed {\n\t\t\tc.check_alias_vs_element_type_of_parent(node, (parent_typ_sym.info as ast.ArrayFixed).elem_type,\n\t\t\t\t'fixed array')\n\t\t}\n\t\t.map {\n\t\t\tinfo := parent_typ_sym.info as ast.Map\n\t\t\tc.check_alias_vs_element_type_of_parent(node, info.key_type, 'map key')\n\t\t\tc.check_alias_vs_element_type_of_parent(node, info.value_type, 'map value')\n\t\t}\n\t\t.sum_type {\n\t\t\t// TODO: decide whether the following should be allowed. Note that it currently works,\n\t\t\t// while `type Sum = int | Sum` is explicitly disallowed:\n\t\t\t// type Sum = int | Alias\n\t\t\t// type Alias = Sum\n\t\t}\n\t\t.none_ {\n\t\t\tc.error('cannot create a type alias of `none` as it is a value', node.type_pos)\n\t\t}\n\t\t// The rest of the parent symbol kinds are also allowed, since they are either primitive types,\n\t\t// that in turn do not allow recursion, or are abstract enough so that they can not be checked at comptime:\n\t\telse {}\n\t\t/*\n\t\t.voidptr, .byteptr, .charptr {}\n\t\t.char, .rune, .bool {}\n\t\t.string, .enum_, .none_, .any {}\n\t\t.i8, .i16, .int, .i64, .isize {}\n\t\t.u8, .u16, .u32, .u64, .usize {}\n\t\t.f32, .f64 {}\n\t\t.interface_ {}\n\t\t.generic_inst {}\n\t\t.aggregate {}\n\t\t*/\n\t}\n}\n\nfn (mut c Checker) check_alias_vs_element_type_of_parent(node ast.AliasTypeDecl, element_type_of_parent ast.Type, label string) {\n\tif node.typ.idx() != element_type_of_parent.idx() {\n\t\treturn\n\t}\n\tc.error('recursive declarations of aliases are not allowed - the alias `${node.name}` is used in the ${label}',\n\t\tnode.type_pos)\n}\n\nfn (mut c Checker) fn_type_decl(node ast.FnTypeDecl) {\n\tc.check_valid_pascal_case(node.name, 'fn type', node.pos)\n\ttyp_sym := c.table.sym(node.typ)\n\tfn_typ_info := typ_sym.info as ast.FnType\n\tfn_info := fn_typ_info.func\n\tc.ensure_type_exists(fn_info.return_type, fn_info.return_type_pos)\n\tret_sym := c.table.sym(fn_info.return_type)\n\tif ret_sym.kind == .placeholder {\n\t\tc.error('unknown type `${ret_sym.name}`', fn_info.return_type_pos)\n\t}\n\tfor arg in fn_info.params {\n\t\tif !c.ensure_type_exists(arg.typ, arg.type_pos) {\n\t\t\treturn\n\t\t}\n\t\targ_sym := c.table.sym(arg.typ)\n\t\tif arg_sym.kind == .placeholder {\n\t\t\tc.error('unknown type `${arg_sym.name}`', arg.type_pos)\n\t\t}\n\t}\n}\n\nfn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) {\n\tc.check_valid_pascal_case(node.name, 'sum type', node.pos)\n\tmut names_used := []string{}\n\tfor variant in node.variants {\n\t\tc.ensure_type_exists(variant.typ, variant.pos)\n\t\tsym := c.table.sym(variant.typ)\n\t\tif variant.typ.is_ptr() || (sym.info is ast.Alias && sym.info.parent_type.is_ptr()) {\n\t\t\tvariant_name := sym.name.all_after_last('.')\n\t\t\tlb, rb := if sym.kind == .struct_ { '{', '}' } else { '(', ')' }\n\t\t\tmsg := if sym.info is ast.Alias && sym.info.parent_type.is_ptr() {\n\t\t\t\t'alias as non-reference type'\n\t\t\t} else {\n\t\t\t\t'the sum type with non-reference types'\n\t\t\t}\n\t\t\tc.add_error_detail('declare ${msg}: `${node.name} = ${variant_name} | ...`\nand use a reference to the sum type instead: `var := &${node.name}(${variant_name}${lb}val${rb})`')\n\t\t\tc.error('sum type cannot hold a reference type', variant.pos)\n\t\t}\n\t\tif sym.name in names_used {\n\t\t\tc.error('sum type ${node.name} cannot hold the type `${sym.name}` more than once',\n\t\t\t\tvariant.pos)\n\t\t} else if sym.kind in [.placeholder, .int_literal, .float_literal] {\n\t\t\tc.error('unknown type `${sym.name}`', variant.pos)\n\t\t} else if sym.kind == .interface_ && sym.language != .js {\n\t\t\tc.error('sum type cannot hold an interface', variant.pos)\n\t\t} else if sym.kind == .struct_ && sym.language == .js {\n\t\t\tc.error('sum type cannot hold a JS struct', variant.pos)\n\t\t} else if sym.info is ast.Struct {\n\t\t\tif sym.info.is_generic {\n\t\t\t\tif !variant.typ.has_flag(.generic) {\n\t\t\t\t\tc.error('generic struct `${sym.name}` must specify generic type names, e.g. ${sym.name}[T]',\n\t\t\t\t\t\tvariant.pos)\n\t\t\t\t}\n\t\t\t\tif node.generic_types.len == 0 {\n\t\t\t\t\tc.error('generic sumtype `${node.name}` must specify generic type names, e.g. ${node.name}[T]',\n\t\t\t\t\t\tnode.name_pos)\n\t\t\t\t} else {\n\t\t\t\t\tfor typ in sym.info.generic_types {\n\t\t\t\t\t\tif typ !in node.generic_types {\n\t\t\t\t\t\t\tsumtype_type_names := node.generic_types.map(c.table.type_to_str(it)).join(', ')\n\t\t\t\t\t\t\tgeneric_sumtype_name := '${node.name}[${sumtype_type_names}]'\n\t\t\t\t\t\t\tvariant_type_names := sym.info.generic_types.map(c.table.type_to_str(it)).join(', ')\n\t\t\t\t\t\t\tgeneric_variant_name := '${sym.name}[${variant_type_names}]'\n\t\t\t\t\t\t\tc.error('generic type name `${c.table.sym(typ).name}` of generic struct `${generic_variant_name}` is not mentioned in sumtype `${generic_sumtype_name}`',\n\t\t\t\t\t\t\t\tvariant.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if sym.info is ast.FnType {\n\t\t\tif sym.info.func.generic_names.len > 0 {\n\t\t\t\tif !variant.typ.has_flag(.generic) {\n\t\t\t\t\tc.error('generic fntype `${sym.name}` must specify generic type names, e.g. ${sym.name}[T]',\n\t\t\t\t\t\tvariant.pos)\n\t\t\t\t}\n\t\t\t\tif node.generic_types.len == 0 {\n\t\t\t\t\tc.error('generic sumtype `${node.name}` must specify generic type names, e.g. ${node.name}[T]',\n\t\t\t\t\t\tnode.name_pos)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif c.table.sym(sym.info.func.return_type).name.ends_with('.${node.name}') {\n\t\t\t\tc.error('sum type `${node.name}` cannot be defined recursively', variant.pos)\n\t\t\t}\n\t\t\tfor param in sym.info.func.params {\n\t\t\t\tif c.table.sym(param.typ).name.ends_with('.${node.name}') {\n\t\t\t\t\tc.error('sum type `${node.name}` cannot be defined recursively', variant.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif sym.name.trim_string_left(sym.mod + '.') == node.name {\n\t\t\tc.error('sum type cannot hold itself', variant.pos)\n\t\t}\n\t\tnames_used << sym.name\n\t}\n}\n\nfn (mut c Checker) expand_iface_embeds(idecl &ast.InterfaceDecl, level int, iface_embeds []ast.InterfaceEmbedding) []ast.InterfaceEmbedding {\n\t// eprintln('> expand_iface_embeds: idecl.name: $idecl.name | level: $level | iface_embeds.len: $iface_embeds.len')\n\tif level > checker.iface_level_cutoff_limit {\n\t\tc.error('too many interface embedding levels: ${level}, for interface `${idecl.name}`',\n\t\t\tidecl.pos)\n\t\treturn []\n\t}\n\tif iface_embeds.len == 0 {\n\t\treturn []\n\t}\n\tmut res := map[int]ast.InterfaceEmbedding{}\n\tmut ares := []ast.InterfaceEmbedding{}\n\tfor ie in iface_embeds {\n\t\tif iface_decl := c.table.interfaces[ie.typ] {\n\t\t\tmut list := iface_decl.embeds.clone()\n\t\t\tif !iface_decl.are_embeds_expanded {\n\t\t\t\tlist = c.expand_iface_embeds(idecl, level + 1, iface_decl.embeds)\n\t\t\t\tunsafe {\n\t\t\t\t\tc.table.interfaces[ie.typ].embeds = list\n\t\t\t\t}\n\t\t\t\tunsafe {\n\t\t\t\t\tc.table.interfaces[ie.typ].are_embeds_expanded = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor partial in list {\n\t\t\t\tres[partial.typ] = partial\n\t\t\t}\n\t\t}\n\t\tres[ie.typ] = ie\n\t}\n\tfor _, v in res {\n\t\tares << v\n\t}\n\treturn ares\n}\n\n// returns name and position of variable that needs write lock\n// also sets `is_changed` to true (TODO update the name to reflect this?)\nfn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) {\n\tmut to_lock := '' // name of variable that needs lock\n\tmut pos := token.Pos{} // and its position\n\tmut explicit_lock_needed := false\n\tmatch mut expr {\n\t\tast.CastExpr {\n\t\t\t// TODO\n\t\t\treturn '', expr.pos\n\t\t}\n\t\tast.ComptimeSelector {\n\t\t\tmut expr_left := expr.left\n\t\t\tif mut expr.left is ast.Ident {\n\t\t\t\tif mut expr.left.obj is ast.Var {\n\t\t\t\t\tif expr.left.obj.ct_type_var != .generic_param {\n\t\t\t\t\t\tc.fail_if_immutable(mut expr_left)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn '', expr.pos\n\t\t}\n\t\tast.Ident {\n\t\t\tif mut expr.obj is ast.Var {\n\t\t\t\tif !expr.obj.is_mut && !c.pref.translated && !c.file.is_translated\n\t\t\t\t\t&& !c.inside_unsafe {\n\t\t\t\t\tif c.inside_anon_fn {\n\t\t\t\t\t\tc.error('the closure copy of `${expr.name}` is immutable, declare it with `mut` to make it mutable',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.error('`${expr.name}` is immutable, declare it with `mut` to make it mutable',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\texpr.obj.is_changed = true\n\t\t\t\tif expr.obj.typ.share() == .shared_t {\n\t\t\t\t\tif expr.name !in c.locked_names {\n\t\t\t\t\t\tif c.locked_names.len > 0 || c.rlocked_names.len > 0 {\n\t\t\t\t\t\t\tif expr.name in c.rlocked_names {\n\t\t\t\t\t\t\t\tc.error('${expr.name} has an `rlock` but needs a `lock`',\n\t\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tc.error('${expr.name} must be added to the `lock` list above',\n\t\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tto_lock = expr.name\n\t\t\t\t\t\tpos = expr.pos\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if expr.obj is ast.ConstField && expr.name in c.const_names {\n\t\t\t\tif !c.inside_unsafe && !c.pref.translated {\n\t\t\t\t\t// TODO fix this in c2v, do not allow modification of all consts\n\t\t\t\t\t// in translated code\n\t\t\t\t\tc.error('cannot modify constant `${expr.name}`', expr.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.IndexExpr {\n\t\t\tif expr.left_type == 0 {\n\t\t\t\treturn to_lock, pos\n\t\t\t}\n\t\t\tleft_sym := c.table.sym(expr.left_type)\n\t\t\tmut elem_type := ast.Type(0)\n\t\t\tmut kind := ''\n\t\t\tmatch left_sym.info {\n\t\t\t\tast.Array {\n\t\t\t\t\telem_type, kind = left_sym.info.elem_type, 'array'\n\t\t\t\t}\n\t\t\t\tast.ArrayFixed {\n\t\t\t\t\telem_type, kind = left_sym.info.elem_type, 'fixed array'\n\t\t\t\t}\n\t\t\t\tast.Map {\n\t\t\t\t\telem_type, kind = left_sym.info.value_type, 'map'\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t\tif elem_type.has_flag(.shared_f) {\n\t\t\t\tc.error('you have to create a handle and `lock` it to modify `shared` ${kind} element',\n\t\t\t\t\texpr.left.pos().extend(expr.pos))\n\t\t\t}\n\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.left)\n\t\t}\n\t\tast.ParExpr {\n\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.expr)\n\t\t}\n\t\tast.PrefixExpr {\n\t\t\tif expr.op == .mul && expr.right is ast.Ident {\n\t\t\t\t// Do not fail if dereference is immutable:\n\t\t\t\t// `*x = foo()` doesn't modify `x`\n\t\t\t} else {\n\t\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.right)\n\t\t\t}\n\t\t}\n\t\tast.PostfixExpr {\n\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.expr)\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\tif expr.expr_type == 0 {\n\t\t\t\treturn '', expr.pos\n\t\t\t}\n\t\t\t// retrieve ast.Field\n\t\t\tif !c.ensure_type_exists(expr.expr_type, expr.pos) {\n\t\t\t\treturn '', expr.pos\n\t\t\t}\n\t\t\tmut typ_sym := c.table.final_sym(c.unwrap_generic(expr.expr_type))\n\t\t\tmatch typ_sym.kind {\n\t\t\t\t.struct_ {\n\t\t\t\t\tmut has_field := true\n\t\t\t\t\tmut field_info := c.table.find_field_with_embeds(typ_sym, expr.field_name) or {\n\t\t\t\t\t\thas_field = false\n\t\t\t\t\t\tast.StructField{}\n\t\t\t\t\t}\n\t\t\t\t\tif !has_field {\n\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\tc.error('unknown field `${type_str}.${expr.field_name}`', expr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t\tif field_info.typ.has_flag(.shared_f) {\n\t\t\t\t\t\texpr_name := '${expr.expr}.${expr.field_name}'\n\t\t\t\t\t\tif expr_name !in c.locked_names {\n\t\t\t\t\t\t\tif c.locked_names.len > 0 || c.rlocked_names.len > 0 {\n\t\t\t\t\t\t\t\tif expr_name in c.rlocked_names {\n\t\t\t\t\t\t\t\t\tc.error('${expr_name} has an `rlock` but needs a `lock`',\n\t\t\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tc.error('${expr_name} must be added to the `lock` list above',\n\t\t\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tto_lock = expr_name\n\t\t\t\t\t\t\tpos = expr.pos\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif !field_info.is_mut && !c.pref.translated && !c.file.is_translated {\n\t\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\t\tc.error('field `${expr.field_name}` of struct `${type_str}` is immutable',\n\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.expr)\n\t\t\t\t\t}\n\t\t\t\t\tif to_lock != '' {\n\t\t\t\t\t\t// No automatic lock for struct access\n\t\t\t\t\t\texplicit_lock_needed = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t.interface_ {\n\t\t\t\t\tinterface_info := typ_sym.info as ast.Interface\n\t\t\t\t\tmut field_info := interface_info.find_field(expr.field_name) or {\n\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\tc.error('unknown field `${type_str}.${expr.field_name}`', expr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t\tif !field_info.is_mut {\n\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\tc.error('field `${expr.field_name}` of interface `${type_str}` is immutable',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t\tc.fail_if_immutable(mut expr.expr)\n\t\t\t\t}\n\t\t\t\t.sum_type {\n\t\t\t\t\tsumtype_info := typ_sym.info as ast.SumType\n\t\t\t\t\tmut field_info := sumtype_info.find_field(expr.field_name) or {\n\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\tc.error('unknown field `${type_str}.${expr.field_name}`', expr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t\tif !field_info.is_mut {\n\t\t\t\t\t\ttype_str := c.table.type_to_str(expr.expr_type)\n\t\t\t\t\t\tc.error('field `${expr.field_name}` of sumtype `${type_str}` is immutable',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t\tc.fail_if_immutable(mut expr.expr)\n\t\t\t\t}\n\t\t\t\t.array, .string {\n\t\t\t\t\t// should only happen in `builtin` and unsafe blocks\n\t\t\t\t\tinside_builtin := c.file.mod.name == 'builtin'\n\t\t\t\t\tif !inside_builtin && !c.inside_unsafe {\n\t\t\t\t\t\tc.error('`${typ_sym.kind}` can not be modified', expr.pos)\n\t\t\t\t\t\treturn '', expr.pos\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t.aggregate, .placeholder {\n\t\t\t\t\tc.fail_if_immutable(mut expr.expr)\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tc.error('unexpected symbol `${typ_sym.kind}`', expr.pos)\n\t\t\t\t\treturn '', expr.pos\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.CallExpr {\n\t\t\t// TODO: should only work for builtin method\n\t\t\tif expr.name == 'slice' {\n\t\t\t\tto_lock, pos = c.fail_if_immutable(mut expr.left)\n\t\t\t\tif to_lock != '' {\n\t\t\t\t\t// No automatic lock for array slicing (yet(?))\n\t\t\t\t\texplicit_lock_needed = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.ArrayInit {\n\t\t\tc.error('array literal can not be modified', expr.pos)\n\t\t\treturn '', expr.pos\n\t\t}\n\t\tast.StructInit {\n\t\t\treturn '', expr.pos\n\t\t}\n\t\tast.InfixExpr {\n\t\t\treturn '', expr.pos\n\t\t}\n\t\telse {\n\t\t\tif !expr.is_pure_literal() {\n\t\t\t\tc.error('unexpected expression `${expr.type_name()}`', expr.pos())\n\t\t\t\treturn '', expr.pos()\n\t\t\t}\n\t\t}\n\t}\n\tif explicit_lock_needed {\n\t\tc.error('`${to_lock}` is `shared` and needs explicit lock for `${expr.type_name()}`',\n\t\t\tpos)\n\t\tto_lock = ''\n\t}\n\treturn to_lock, pos\n}\n\nfn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos token.Pos) bool {\n\tif typ == interface_type {\n\t\treturn true\n\t}\n\t$if debug_interface_type_implements ? {\n\t\teprintln('> type_implements typ: ${typ.debug()} (`${c.table.type_to_str(typ)}`) | inter_typ: ${interface_type.debug()} (`${c.table.type_to_str(interface_type)}`)')\n\t}\n\tutyp := c.unwrap_generic(typ)\n\tstyp := c.table.type_to_str(utyp)\n\ttyp_sym := c.table.sym(utyp)\n\tmut inter_sym := c.table.sym(interface_type)\n\tif !inter_sym.is_pub && inter_sym.mod !in [typ_sym.mod, c.mod] && typ_sym.mod != 'builtin' {\n\t\tc.error('`${styp}` cannot implement private interface `${inter_sym.name}` of other module',\n\t\t\tpos)\n\t\treturn false\n\t}\n\n\t// small hack for JS.Any type. Since `any` in regular V is getting deprecated we have our own JS.Any type for JS backend.\n\tif typ_sym.name == 'JS.Any' {\n\t\treturn true\n\t}\n\tif mut inter_sym.info is ast.Interface {\n\t\tmut generic_type := interface_type\n\t\tmut generic_info := inter_sym.info\n\t\tif inter_sym.info.parent_type.has_flag(.generic) {\n\t\t\tparent_sym := c.table.sym(inter_sym.info.parent_type)\n\t\t\tif parent_sym.info is ast.Interface {\n\t\t\t\tgeneric_type = inter_sym.info.parent_type\n\t\t\t\tgeneric_info = parent_sym.info\n\t\t\t}\n\t\t}\n\t\tmut inferred_type := interface_type\n\t\tif generic_info.is_generic {\n\t\t\tinferred_type = c.resolve_generic_interface(typ, generic_type, pos)\n\t\t\tif inferred_type == 0 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\tif inter_sym.info.is_generic {\n\t\t\tif inferred_type == interface_type {\n\t\t\t\t// terminate early, since otherwise we get an infinite recursion/segfault:\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn c.type_implements(typ, inferred_type, pos)\n\t\t}\n\t}\n\t// do not check the same type more than once\n\tif mut inter_sym.info is ast.Interface {\n\t\tfor t in inter_sym.info.types {\n\t\t\tif t.idx() == utyp.idx() {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\tif utyp.idx() == interface_type.idx() {\n\t\t// same type -> already casted to the interface\n\t\treturn true\n\t}\n\tif interface_type.idx() == ast.error_type_idx && utyp.idx() == ast.none_type_idx {\n\t\t// `none` \"implements\" the Error interface\n\t\treturn true\n\t}\n\tif typ_sym.kind == .interface_ && inter_sym.kind == .interface_ && !styp.starts_with('JS.')\n\t\t&& !inter_sym.name.starts_with('JS.') {\n\t\tc.error('cannot implement interface `${inter_sym.name}` with a different interface `${styp}`',\n\t\t\tpos)\n\t}\n\timethods := if inter_sym.kind == .interface_ {\n\t\t(inter_sym.info as ast.Interface).methods\n\t} else {\n\t\tinter_sym.methods\n\t}\n\t// voidptr is an escape hatch, it should be allowed to be passed\n\tif utyp != ast.voidptr_type && utyp != ast.nil_type {\n\t\tmut are_methods_implemented := true\n\n\t\t// Verify methods\n\t\tfor imethod in imethods {\n\t\t\tmethod := c.table.find_method_with_embeds(typ_sym, imethod.name) or {\n\t\t\t\t// >> Hack to allow old style custom error implementations\n\t\t\t\t// TODO: remove once deprecation period for `IError` methods has ended\n\t\t\t\tif inter_sym.idx == ast.error_type_idx\n\t\t\t\t\t&& (imethod.name == 'msg' || imethod.name == 'code') {\n\t\t\t\t\tc.note(\"`${styp}` doesn't implement method `${imethod.name}` of interface `${inter_sym.name}`. The usage of fields is being deprecated in favor of methods.\",\n\t\t\t\t\t\tpos)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\t// <<\n\n\t\t\t\ttyp_sym.find_method_with_generic_parent(imethod.name) or {\n\t\t\t\t\tc.error(\"`${styp}` doesn't implement method `${imethod.name}` of interface `${inter_sym.name}`\",\n\t\t\t\t\t\tpos)\n\t\t\t\t\tare_methods_implemented = false\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tmsg := c.table.is_same_method(imethod, method)\n\t\t\tif msg.len > 0 {\n\t\t\t\tsig := c.table.fn_signature(imethod, skip_receiver: false)\n\t\t\t\ttyp_sig := c.table.fn_signature(method, skip_receiver: false)\n\t\t\t\tc.add_error_detail('${inter_sym.name} has `${sig}`')\n\t\t\t\tc.add_error_detail('         ${typ_sym.name} has `${typ_sig}`')\n\t\t\t\tc.error('`${styp}` incorrectly implements method `${imethod.name}` of interface `${inter_sym.name}`: ${msg}',\n\t\t\t\t\tpos)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif !are_methods_implemented {\n\t\t\treturn false\n\t\t}\n\t}\n\t// Verify fields\n\tif mut inter_sym.info is ast.Interface {\n\t\tfor ifield in inter_sym.info.fields {\n\t\t\tif field := c.table.find_field_with_embeds(typ_sym, ifield.name) {\n\t\t\t\tif ifield.typ != field.typ {\n\t\t\t\t\texp := c.table.type_to_str(ifield.typ)\n\t\t\t\t\tgot := c.table.type_to_str(field.typ)\n\t\t\t\t\tc.error('`${styp}` incorrectly implements field `${ifield.name}` of interface `${inter_sym.name}`, expected `${exp}`, got `${got}`',\n\t\t\t\t\t\tpos)\n\t\t\t\t\treturn false\n\t\t\t\t} else if ifield.is_mut && !(field.is_mut || field.is_global) {\n\t\t\t\t\tc.error('`${styp}` incorrectly implements interface `${inter_sym.name}`, field `${ifield.name}` must be mutable',\n\t\t\t\t\t\tpos)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// voidptr is an escape hatch, it should be allowed to be passed\n\t\t\tif utyp != ast.voidptr_type && utyp != ast.nil_type {\n\t\t\t\t// >> Hack to allow old style custom error implementations\n\t\t\t\t// TODO: remove once deprecation period for `IError` methods has ended\n\t\t\t\tif inter_sym.idx == ast.error_type_idx\n\t\t\t\t\t&& (ifield.name == 'msg' || ifield.name == 'code') {\n\t\t\t\t\t// do nothing, necessary warnings are already printed\n\t\t\t\t} else {\n\t\t\t\t\t// <<\n\t\t\t\t\tc.error(\"`${styp}` doesn't implement field `${ifield.name}` of interface `${inter_sym.name}`\",\n\t\t\t\t\t\tpos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif utyp != ast.voidptr_type && utyp != ast.nil_type && !inter_sym.info.types.contains(utyp) {\n\t\t\tinter_sym.info.types << utyp\n\t\t}\n\t\tif !inter_sym.info.types.contains(ast.voidptr_type) {\n\t\t\tinter_sym.info.types << ast.voidptr_type\n\t\t}\n\t}\n\treturn true\n}\n\n// helper for expr_or_block_err\nfn is_field_to_description(expr_name string, is_field bool) string {\n\treturn if is_field {\n\t\t'field `${expr_name}` is not'\n\t} else {\n\t\t'function `${expr_name}` does not return'\n\t}\n}\n\nfn (mut c Checker) expr_or_block_err(kind ast.OrKind, expr_name string, pos token.Pos, is_field bool) {\n\tmatch kind {\n\t\t.absent {\n\t\t\t// do nothing, most common case; do not be tempted to move the call to is_field_to_description above it, since that will slow it down\n\t\t}\n\t\t.block {\n\t\t\tobj_does_not_return_or_is_not := is_field_to_description(expr_name, is_field)\n\t\t\tc.error('unexpected `or` block, the ${obj_does_not_return_or_is_not} an Option or a Result',\n\t\t\t\tpos)\n\t\t}\n\t\t.propagate_option {\n\t\t\tobj_does_not_return_or_is_not := is_field_to_description(expr_name, is_field)\n\t\t\tc.error('unexpected `?`, the ${obj_does_not_return_or_is_not} an Option',\n\t\t\t\tpos)\n\t\t}\n\t\t.propagate_result {\n\t\t\tobj_does_not_return_or_is_not := is_field_to_description(expr_name, is_field)\n\t\t\tc.error('unexpected `!`, the ${obj_does_not_return_or_is_not} a Result', pos)\n\t\t}\n\t}\n}\n\n// return the actual type of the expression, once the result or option type is handled\nfn (mut c Checker) check_expr_option_or_result_call(expr ast.Expr, ret_type ast.Type) ast.Type {\n\tmatch expr {\n\t\tast.CallExpr {\n\t\t\tmut expr_ret_type := expr.return_type\n\t\t\tif expr_ret_type != 0 && c.table.sym(expr_ret_type).kind == .alias {\n\t\t\t\tunaliased_ret_type := c.table.unaliased_type(expr_ret_type)\n\t\t\t\tif unaliased_ret_type.has_option_or_result() {\n\t\t\t\t\texpr_ret_type = unaliased_ret_type\n\t\t\t\t}\n\t\t\t}\n\t\t\tif expr_ret_type.has_option_or_result() {\n\t\t\t\treturn_modifier_kind := if expr_ret_type.has_flag(.option) {\n\t\t\t\t\t'an Option'\n\t\t\t\t} else {\n\t\t\t\t\t'a Result'\n\t\t\t\t}\n\t\t\t\treturn_modifier := if expr_ret_type.has_flag(.option) { '?' } else { '!' }\n\t\t\t\tif expr_ret_type.has_flag(.result) && expr.or_block.kind == .absent {\n\t\t\t\t\tif c.inside_defer {\n\t\t\t\t\t\tc.error('${expr.name}() returns ${return_modifier_kind}, so it should have an `or {}` block at the end',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.error('${expr.name}() returns ${return_modifier_kind}, so it should have either an `or {}` block, or `${return_modifier}` at the end',\n\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif expr.or_block.kind != .absent {\n\t\t\t\t\t\tc.check_or_expr(expr.or_block, ret_type, expr_ret_type, expr)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn ret_type.clear_flag(.result)\n\t\t\t} else {\n\t\t\t\tc.expr_or_block_err(expr.or_block.kind, expr.name, expr.or_block.pos,\n\t\t\t\t\tfalse)\n\t\t\t}\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\tif c.table.sym(ret_type).kind != .chan {\n\t\t\t\tif expr.typ.has_option_or_result() {\n\t\t\t\t\twith_modifier_kind := if expr.typ.has_flag(.option) {\n\t\t\t\t\t\t'an Option'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t'a Result'\n\t\t\t\t\t}\n\t\t\t\t\twith_modifier := if expr.typ.has_flag(.option) { '?' } else { '!' }\n\t\t\t\t\tif expr.typ.has_flag(.result) && expr.or_block.kind == .absent {\n\t\t\t\t\t\tif c.inside_defer {\n\t\t\t\t\t\t\tc.error('field `${expr.field_name}` is ${with_modifier_kind}, so it should have an `or {}` block at the end',\n\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tc.error('field `${expr.field_name}` is ${with_modifier_kind}, so it should have either an `or {}` block, or `${with_modifier}` at the end',\n\t\t\t\t\t\t\t\texpr.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif expr.or_block.kind != .absent {\n\t\t\t\t\t\t\tc.check_or_expr(expr.or_block, ret_type, expr.typ, expr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn ret_type.clear_flag(.result)\n\t\t\t\t} else {\n\t\t\t\t\tc.expr_or_block_err(expr.or_block.kind, expr.field_name, expr.or_block.pos,\n\t\t\t\t\t\ttrue)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.IndexExpr {\n\t\t\tif expr.or_expr.kind != .absent {\n\t\t\t\tmut return_none_or_error := false\n\t\t\t\tif expr.or_expr.stmts.len > 0 {\n\t\t\t\t\tlast_stmt := expr.or_expr.stmts.last()\n\t\t\t\t\tif last_stmt is ast.ExprStmt {\n\t\t\t\t\t\tif c.inside_return && last_stmt.typ in [ast.none_type, ast.error_type] {\n\t\t\t\t\t\t\treturn_none_or_error = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif return_none_or_error {\n\t\t\t\t\tc.check_expr_option_or_result_call(expr.or_expr, c.table.cur_fn.return_type)\n\t\t\t\t} else {\n\t\t\t\t\tc.check_or_expr(expr.or_expr, ret_type, ret_type.set_flag(.result),\n\t\t\t\t\t\texpr)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.CastExpr {\n\t\t\tc.check_expr_option_or_result_call(expr.expr, ret_type)\n\t\t}\n\t\tast.AsCast {\n\t\t\tc.check_expr_option_or_result_call(expr.expr, ret_type)\n\t\t}\n\t\tast.ParExpr {\n\t\t\tc.check_expr_option_or_result_call(expr.expr, ret_type)\n\t\t}\n\t\telse {}\n\t}\n\treturn ret_type\n}\n\nfn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return_type ast.Type, expr ast.Expr) {\n\tif node.kind == .propagate_option {\n\t\tif c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.option)\n\t\t\t&& !c.table.cur_fn.is_main && !c.table.cur_fn.is_test && !c.inside_const {\n\t\t\tc.add_instruction_for_option_type()\n\t\t\tif expr is ast.Ident {\n\t\t\t\tc.error('to propagate the Option, `${c.table.cur_fn.name}` must return an Option type',\n\t\t\t\t\texpr.pos)\n\t\t\t} else {\n\t\t\t\tc.error('to propagate the call, `${c.table.cur_fn.name}` must return an Option type',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t}\n\t\tif expr !is ast.Ident && !expr_return_type.has_flag(.option) {\n\t\t\tif expr_return_type.has_flag(.result) {\n\t\t\t\tc.error('propagating a Result like an Option is deprecated, use `foo()!` instead of `foo()?`',\n\t\t\t\t\tnode.pos)\n\t\t\t} else {\n\t\t\t\tc.error('to propagate an Option, the call must also return an Option type',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tif node.kind == .propagate_result {\n\t\tif c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.result)\n\t\t\t&& !c.table.cur_fn.is_main && !c.table.cur_fn.is_test && !c.inside_const {\n\t\t\tc.add_instruction_for_result_type()\n\t\t\tc.error('to propagate the call, `${c.table.cur_fn.name}` must return a Result type',\n\t\t\t\tnode.pos)\n\t\t}\n\t\tif !expr_return_type.has_flag(.result) {\n\t\t\tc.error('to propagate a Result, the call must also return a Result type',\n\t\t\t\tnode.pos)\n\t\t}\n\t\treturn\n\t}\n\tif node.stmts.len == 0 {\n\t\tif ret_type != ast.void_type {\n\t\t\t// x := f() or {}\n\t\t\tc.error('assignment requires a non empty `or {}` block', node.pos)\n\t\t}\n\t\t// allow `f() or {}`\n\t\treturn\n\t}\n\tmut last_stmt := node.stmts.last()\n\tc.check_or_last_stmt(mut last_stmt, ret_type, expr_return_type.clear_option_and_result())\n}\n\nfn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr_return_type ast.Type) {\n\tif ret_type != ast.void_type {\n\t\tmatch mut stmt {\n\t\t\tast.ExprStmt {\n\t\t\t\tc.expected_type = ret_type\n\t\t\t\tc.expected_or_type = ret_type.clear_option_and_result()\n\t\t\t\tlast_stmt_typ := c.expr(mut stmt.expr)\n\n\t\t\t\tif last_stmt_typ.has_flag(.option) || last_stmt_typ == ast.none_type {\n\t\t\t\t\tif stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.None, ast.CastExpr] {\n\t\t\t\t\t\texpected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())\n\t\t\t\t\t\tgot_type_name := c.table.type_to_str(last_stmt_typ)\n\t\t\t\t\t\tc.error('`or` block must provide a value of type `${expected_type_name}`, not `${got_type_name}`',\n\t\t\t\t\t\t\tstmt.expr.pos())\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tc.expected_or_type = ast.void_type\n\t\t\t\ttype_fits := c.check_types(last_stmt_typ, ret_type)\n\t\t\t\t\t&& last_stmt_typ.nr_muls() == ret_type.nr_muls()\n\t\t\t\tis_noreturn := is_noreturn_callexpr(stmt.expr)\n\t\t\t\tif type_fits || is_noreturn {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif stmt.typ == ast.void_type {\n\t\t\t\t\tif mut stmt.expr is ast.IfExpr {\n\t\t\t\t\t\tfor mut branch in stmt.expr.branches {\n\t\t\t\t\t\t\tif branch.stmts.len > 0 {\n\t\t\t\t\t\t\t\tmut stmt_ := branch.stmts.last()\n\t\t\t\t\t\t\t\tc.check_or_last_stmt(mut stmt_, ret_type, expr_return_type)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t} else if mut stmt.expr is ast.MatchExpr {\n\t\t\t\t\t\tfor mut branch in stmt.expr.branches {\n\t\t\t\t\t\t\tif branch.stmts.len > 0 {\n\t\t\t\t\t\t\t\tmut stmt_ := branch.stmts.last()\n\t\t\t\t\t\t\t\tc.check_or_last_stmt(mut stmt_, ret_type, expr_return_type)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\texpected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())\n\t\t\t\t\tc.error('`or` block must provide a default value of type `${expected_type_name}`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)',\n\t\t\t\t\t\tstmt.expr.pos())\n\t\t\t\t} else {\n\t\t\t\t\tif ret_type.is_ptr() && last_stmt_typ.is_pointer()\n\t\t\t\t\t\t&& c.table.sym(last_stmt_typ).kind == .voidptr {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif last_stmt_typ == ast.none_type_idx && ret_type.has_flag(.option) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\ttype_name := c.table.type_to_str(last_stmt_typ)\n\t\t\t\t\texpected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())\n\t\t\t\t\tc.error('wrong return type `${type_name}` in the `or {}` block, expected `${expected_type_name}`',\n\t\t\t\t\t\tstmt.expr.pos())\n\t\t\t\t}\n\t\t\t}\n\t\t\tast.BranchStmt {\n\t\t\t\tif stmt.kind !in [.key_continue, .key_break] {\n\t\t\t\t\tc.error('only break/continue is allowed as a branch statement in the end of an `or {}` block',\n\t\t\t\t\t\tstmt.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tast.Return {}\n\t\t\telse {\n\t\t\t\texpected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())\n\t\t\t\tc.error('last statement in the `or {}` block should be an expression of type `${expected_type_name}` or exit parent scope',\n\t\t\t\t\tstmt.pos)\n\t\t\t}\n\t\t}\n\t} else if mut stmt is ast.ExprStmt {\n\t\tmatch mut stmt.expr {\n\t\t\tast.IfExpr {\n\t\t\t\tfor mut branch in stmt.expr.branches {\n\t\t\t\t\tif branch.stmts.len > 0 {\n\t\t\t\t\t\tmut stmt_ := branch.stmts.last()\n\t\t\t\t\t\tc.check_or_last_stmt(mut stmt_, ret_type, expr_return_type)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tast.MatchExpr {\n\t\t\t\tfor mut branch in stmt.expr.branches {\n\t\t\t\t\tif branch.stmts.len > 0 {\n\t\t\t\t\t\tmut stmt_ := branch.stmts.last()\n\t\t\t\t\t\tc.check_or_last_stmt(mut stmt_, ret_type, expr_return_type)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif stmt.typ == ast.void_type || expr_return_type == ast.void_type {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif is_noreturn_callexpr(stmt.expr) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif c.check_types(stmt.typ, expr_return_type) {\n\t\t\t\t\tif stmt.typ.is_ptr() == expr_return_type.is_ptr()\n\t\t\t\t\t\t|| (expr_return_type.is_ptr() && stmt.typ.is_pointer()\n\t\t\t\t\t\t&& c.table.sym(stmt.typ).kind == .voidptr) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// opt_returning_string() or { ... 123 }\n\t\t\t\ttype_name := c.table.type_to_str(stmt.typ)\n\t\t\t\texpr_return_type_name := c.table.type_to_str(expr_return_type)\n\t\t\t\tc.error('the default expression type in the `or` block should be `${expr_return_type_name}`, instead you gave a value of type `${type_name}`',\n\t\t\t\t\tstmt.expr.pos())\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {\n\tprevent_sum_type_unwrapping_once := c.prevent_sum_type_unwrapping_once\n\tc.prevent_sum_type_unwrapping_once = false\n\n\tusing_new_err_struct_save := c.using_new_err_struct\n\t// TODO remove; this avoids a breaking change in syntax\n\tif '${node.expr}' == 'err' {\n\t\tc.using_new_err_struct = true\n\t}\n\n\t// T.name, typeof(expr).name\n\tmut name_type := 0\n\tmut node_expr := node.expr\n\tmatch mut node.expr {\n\t\tast.Ident {\n\t\t\tname := node.expr.name\n\t\t\tvalid_generic := util.is_generic_type_name(name) && c.table.cur_fn != unsafe { nil }\n\t\t\t\t&& name in c.table.cur_fn.generic_names\n\t\t\tif valid_generic {\n\t\t\t\tname_type = ast.Type(c.table.find_type_idx(name)).set_flag(.generic)\n\t\t\t}\n\t\t}\n\t\tast.TypeOf {\n\t\t\t// TODO: fix this weird case, since just `typeof(x)` is `string`, but `|typeof(x).| propertyname` should be the actual type,\n\t\t\t// so that we can get other metadata properties of the type, depending on `propertyname` (one of `name` or `idx` for now).\n\t\t\t// A better alternative would be a new `meta(x).propertyname`, that does not have a `meta(x)` case (an error),\n\t\t\t// or if it does, it should be a normal constant struct value, just filled at comptime.\n\t\t\tc.expr(mut node_expr)\n\t\t\tname_type = node.expr.typ\n\t\t}\n\t\tast.AsCast {\n\t\t\tc.add_error_detail('for example `(${node.expr.expr} as ${c.table.type_to_str(node.expr.typ)}).${node.field_name}`')\n\t\t\tc.error('indeterminate `as` cast, use parenthesis to clarity', node.expr.pos)\n\t\t}\n\t\telse {}\n\t}\n\tif name_type > 0 {\n\t\tnode.name_type = name_type\n\t\tmatch node.gkind_field {\n\t\t\t.name {\n\t\t\t\treturn ast.string_type\n\t\t\t}\n\t\t\t.typ {\n\t\t\t\treturn ast.int_type\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif node.field_name == 'name' {\n\t\t\t\t\treturn ast.string_type\n\t\t\t\t} else if node.field_name == 'idx' {\n\t\t\t\t\treturn ast.int_type\n\t\t\t\t}\n\t\t\t\tc.error('invalid field `.${node.field_name}` for type `${node.expr}`',\n\t\t\t\t\tnode.pos)\n\t\t\t\treturn ast.string_type\n\t\t\t}\n\t\t}\n\t}\n\t// evaluates comptime field.<name> (from T.fields)\n\tif c.comptime.check_comptime_is_field_selector(node) {\n\t\tif c.comptime.check_comptime_is_field_selector_bool(node) {\n\t\t\tnode.expr_type = ast.bool_type\n\t\t\treturn node.expr_type\n\t\t}\n\t}\n\told_selector_expr := c.inside_selector_expr\n\tc.inside_selector_expr = true\n\tmut typ := c.expr(mut node.expr)\n\tif node.expr.is_auto_deref_var() {\n\t\tif mut node.expr is ast.Ident {\n\t\t\tif mut node.expr.obj is ast.Var {\n\t\t\t\ttyp = node.expr.obj.typ\n\t\t\t}\n\t\t}\n\t}\n\tc.inside_selector_expr = old_selector_expr\n\tc.using_new_err_struct = using_new_err_struct_save\n\tif typ == ast.void_type_idx {\n\t\t// This means that the field has an undefined type.\n\t\t// This error was handled before.\n\t\tc.error('`${node.expr}` does not return a value', node.pos)\n\t\tnode.expr_type = ast.void_type\n\t\treturn ast.void_type\n\t} else if c.comptime.inside_comptime_for && typ == c.enum_data_type\n\t\t&& node.field_name == 'value' {\n\t\t// for comp-time enum.values\n\t\tnode.expr_type = c.comptime.type_map['${c.comptime.comptime_for_enum_var}.typ']\n\t\tnode.typ = typ\n\t\treturn node.expr_type\n\t}\n\tnode.expr_type = typ\n\tif !(node.expr is ast.Ident && node.expr.kind == .constant) {\n\t\tif node.expr_type.has_flag(.option) {\n\t\t\tc.error('cannot access fields of an Option, handle the error with `or {...}` or propagate it with `?`',\n\t\t\t\tnode.pos)\n\t\t} else if node.expr_type.has_flag(.result) {\n\t\t\tc.error('cannot access fields of a Result, handle the error with `or {...}` or propagate it with `!`',\n\t\t\t\tnode.pos)\n\t\t}\n\t}\n\tfield_name := node.field_name\n\tsym := c.table.sym(typ)\n\tif (typ.has_flag(.variadic) || sym.kind == .array_fixed) && field_name == 'len' {\n\t\tnode.typ = ast.int_type\n\t\treturn ast.int_type\n\t}\n\tif sym.kind == .chan {\n\t\tif field_name == 'closed' {\n\t\t\tnode.typ = ast.bool_type\n\t\t\treturn ast.bool_type\n\t\t} else if field_name in ['len', 'cap'] {\n\t\t\tnode.typ = ast.u32_type\n\t\t\treturn ast.u32_type\n\t\t}\n\t}\n\tmut unknown_field_msg := 'type `${sym.name}` has no field named `${field_name}`'\n\tmut has_field := false\n\tmut field := ast.StructField{}\n\tif field_name.len > 0 && field_name[0].is_capital() && sym.info is ast.Struct\n\t\t&& sym.language == .v {\n\t\t// x.Foo.y => access the embedded struct\n\t\tfor embed in sym.info.embeds {\n\t\t\tembed_sym := c.table.sym(embed)\n\t\t\tif embed_sym.embed_name() == field_name {\n\t\t\t\tnode.typ = embed\n\t\t\t\treturn embed\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif f := c.table.find_field(sym, field_name) {\n\t\t\thas_field = true\n\t\t\tfield = f\n\t\t} else {\n\t\t\t// look for embedded field\n\t\t\thas_field = true\n\t\t\tmut embed_types := []ast.Type{}\n\t\t\tfield, embed_types = c.table.find_field_from_embeds(sym, field_name) or {\n\t\t\t\tif err.msg() != '' {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t}\n\t\t\t\thas_field = false\n\t\t\t\tast.StructField{}, []ast.Type{}\n\t\t\t}\n\t\t\tnode.from_embed_types = embed_types\n\t\t\tif sym.kind in [.aggregate, .sum_type] {\n\t\t\t\tunknown_field_msg = err.msg()\n\t\t\t}\n\t\t}\n\t\tif !c.inside_unsafe {\n\t\t\tif sym.info is ast.Struct {\n\t\t\t\tif sym.info.is_union && node.next_token !in token.assign_tokens {\n\t\t\t\t\tif !c.pref.translated && !c.file.is_translated {\n\t\t\t\t\t\tc.warn('reading a union field (or its address) requires `unsafe`',\n\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif typ.has_flag(.generic) && !has_field {\n\t\t\tgs := c.table.sym(c.unwrap_generic(typ))\n\t\t\tif f := c.table.find_field(gs, field_name) {\n\t\t\t\thas_field = true\n\t\t\t\tfield = f\n\t\t\t} else {\n\t\t\t\t// look for embedded field\n\t\t\t\thas_field = true\n\t\t\t\tmut embed_types := []ast.Type{}\n\t\t\t\tfield, embed_types = c.table.find_field_from_embeds(gs, field_name) or {\n\t\t\t\t\tif err.msg() != '' {\n\t\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\t}\n\t\t\t\t\thas_field = false\n\t\t\t\t\tast.StructField{}, []ast.Type{}\n\t\t\t\t}\n\t\t\t\tnode.from_embed_types = embed_types\n\t\t\t\tnode.generic_from_embed_types << embed_types\n\t\t\t}\n\t\t}\n\t}\n\n\t// >> Hack to allow old style custom error implementations\n\t// TODO: remove once deprecation period for `IError` methods has ended\n\tif sym.idx == ast.error_type_idx && !c.is_just_builtin_mod\n\t\t&& (field_name == 'msg' || field_name == 'code') {\n\t\tmethod := c.table.find_method(sym, field_name) or {\n\t\t\tc.error('invalid `IError` interface implementation: ${err}', node.pos)\n\t\t\treturn ast.void_type\n\t\t}\n\t\tc.note('the `.${field_name}` field on `IError` is deprecated, and will be removed after 2022-06-01, use `.${field_name}()` instead.',\n\t\t\tnode.pos)\n\t\treturn method.return_type\n\t}\n\t// <<<\n\n\tif has_field {\n\t\tis_used_outside := sym.mod != c.mod\n\t\tif is_used_outside && !field.is_pub && sym.language != .c {\n\t\t\tunwrapped_sym := c.table.sym(c.unwrap_generic(typ))\n\t\t\tc.error('field `${unwrapped_sym.name}.${field_name}` is not public', node.pos)\n\t\t}\n\t\tfield_sym := c.table.sym(field.typ)\n\t\tif field.is_deprecated && is_used_outside {\n\t\t\tc.deprecate('field', field_name, field.attrs, node.pos)\n\t\t}\n\t\tif field_sym.kind in [.sum_type, .interface_] {\n\t\t\tif !prevent_sum_type_unwrapping_once {\n\t\t\t\tif scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name) {\n\t\t\t\t\treturn scope_field.smartcasts.last()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tnode.typ = field.typ\n\t\tif node.or_block.kind == .block {\n\t\t\tc.expected_or_type = node.typ.clear_option_and_result()\n\t\t\tc.stmts_ending_with_expression(mut node.or_block.stmts)\n\t\t\tc.check_or_expr(node.or_block, node.typ, c.expected_or_type, node)\n\t\t\tc.expected_or_type = ast.void_type\n\t\t}\n\t\treturn field.typ\n\t}\n\tif mut method := sym.find_method_with_generic_parent(field_name) {\n\t\tif c.expected_type != 0 && c.expected_type != ast.none_type {\n\t\t\tfn_type := ast.new_type(c.table.find_or_register_fn_type(method, false, true))\n\t\t\t// if the expected type includes the receiver, don't hide it behind a closure\n\t\t\tif c.check_types(fn_type, c.expected_type) {\n\t\t\t\treturn fn_type\n\t\t\t}\n\t\t}\n\t\treceiver := method.params[0].typ\n\t\tif receiver.nr_muls() > 0 {\n\t\t\tif !c.inside_unsafe {\n\t\t\t\trec_sym := c.table.sym(receiver.set_nr_muls(0))\n\t\t\t\tif !rec_sym.is_heap() {\n\t\t\t\t\tsuggestion := if rec_sym.kind == .struct_ {\n\t\t\t\t\t\t'declaring `${rec_sym.name}` as `[heap]`'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t'wrapping the `${rec_sym.name}` object in a `struct` declared as `[heap]`'\n\t\t\t\t\t}\n\t\t\t\t\tc.error('method `${c.table.type_to_str(receiver.idx())}.${method.name}` cannot be used as a variable outside `unsafe` blocks as its receiver might refer to an object stored on stack. Consider ${suggestion}.',\n\t\t\t\t\t\tnode.expr.pos().extend(node.pos))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmethod.params = method.params[1..]\n\t\tnode.has_hidden_receiver = true\n\t\tmethod.name = ''\n\t\tfn_type := ast.new_type(c.table.find_or_register_fn_type(method, false, true))\n\t\tnode.typ = fn_type\n\t\treturn fn_type\n\t}\n\tif sym.kind !in [.struct_, .aggregate, .interface_, .sum_type] {\n\t\tif sym.kind != .placeholder {\n\t\t\tunwrapped_sym := c.table.sym(c.unwrap_generic(typ))\n\n\t\t\tif unwrapped_sym.kind == .array_fixed && node.field_name == 'len' {\n\t\t\t\tnode.typ = ast.int_type\n\t\t\t\treturn ast.int_type\n\t\t\t}\n\n\t\t\tc.error('`${unwrapped_sym.name}` has no property `${node.field_name}`', node.pos)\n\t\t}\n\t} else {\n\t\tif sym.info is ast.Struct {\n\t\t\tif c.smartcast_mut_pos != token.Pos{} {\n\t\t\t\tc.note('smartcasting requires either an immutable value, or an explicit mut keyword before the value',\n\t\t\t\t\tc.smartcast_mut_pos)\n\t\t\t}\n\t\t\tsuggestion := util.new_suggestion(field_name, sym.info.fields.map(it.name))\n\t\t\tc.error(suggestion.say(unknown_field_msg), node.pos)\n\t\t\treturn ast.void_type\n\t\t}\n\t\tif c.smartcast_mut_pos != token.Pos{} {\n\t\t\tc.note('smartcasting requires either an immutable value, or an explicit mut keyword before the value',\n\t\t\t\tc.smartcast_mut_pos)\n\t\t}\n\t\tif c.smartcast_cond_pos != token.Pos{} {\n\t\t\tc.note('smartcast can only be used on the ident or selector, e.g. match foo, match foo.bar',\n\t\t\t\tc.smartcast_cond_pos)\n\t\t}\n\t\tc.error(unknown_field_msg, node.pos)\n\t}\n\treturn ast.void_type\n}\n\nfn (mut c Checker) const_decl(mut node ast.ConstDecl) {\n\tif node.fields.len == 0 {\n\t\tc.warn('const block must have at least 1 declaration', node.pos)\n\t}\n\tfor mut field in node.fields {\n\t\tif checker.reserved_type_names_chk.matches(util.no_cur_mod(field.name, c.mod)) {\n\t\t\tc.error('invalid use of reserved type `${field.name}` as a const name', field.pos)\n\t\t}\n\t\t// TODO Check const name once the syntax is decided\n\t\tif field.name in c.const_names {\n\t\t\tname_pos := token.Pos{\n\t\t\t\t...field.pos\n\t\t\t\tlen: util.no_cur_mod(field.name, c.mod).len\n\t\t\t}\n\t\t\tc.error('duplicate const `${field.name}`', name_pos)\n\t\t}\n\t\tif field.expr is ast.CallExpr {\n\t\t\tsym := c.table.sym(c.check_expr_option_or_result_call(field.expr, c.expr(mut field.expr)))\n\t\t\tif sym.kind == .multi_return {\n\t\t\t\tc.error('const declarations do not support multiple return values yet',\n\t\t\t\t\tfield.expr.pos())\n\t\t\t}\n\t\t}\n\t\tconst_name := field.name.all_after_last('.')\n\t\tif const_name == c.mod && const_name != 'main' {\n\t\t\tname_pos := token.Pos{\n\t\t\t\t...field.pos\n\t\t\t\tlen: util.no_cur_mod(field.name, c.mod).len\n\t\t\t}\n\t\t\tc.error('duplicate of a module name `${field.name}`', name_pos)\n\t\t}\n\t\tc.const_names << field.name\n\t}\n\tfor i, mut field in node.fields {\n\t\tc.const_deps << field.name\n\t\tprev_const_var := c.const_var\n\t\tc.const_var = unsafe { field }\n\t\tmut typ := c.check_expr_option_or_result_call(field.expr, c.expr(mut field.expr))\n\t\tif ct_value := c.eval_comptime_const_expr(field.expr, 0) {\n\t\t\tfield.comptime_expr_value = ct_value\n\t\t\tif ct_value is u64 {\n\t\t\t\ttyp = ast.u64_type\n\t\t\t}\n\t\t}\n\t\tnode.fields[i].typ = ast.mktyp(typ)\n\t\tif mut field.expr is ast.IfExpr {\n\t\t\tfor branch in field.expr.branches {\n\t\t\t\tif branch.stmts.len > 0 && branch.stmts.last() is ast.ExprStmt\n\t\t\t\t\t&& branch.stmts.last().typ != ast.void_type {\n\t\t\t\t\tfield.expr.is_expr = true\n\t\t\t\t\tfield.expr.typ = (branch.stmts.last() as ast.ExprStmt).typ\n\t\t\t\t\tfield.typ = field.expr.typ\n\t\t\t\t\t// update ConstField object's type in table\n\t\t\t\t\tif mut obj := c.file.global_scope.find(field.name) {\n\t\t\t\t\t\tif mut obj is ast.ConstField {\n\t\t\t\t\t\t\tobj.typ = field.typ\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Check for int overflow\n\t\tif field.typ == ast.int_type {\n\t\t\tif mut field.expr is ast.IntegerLiteral {\n\t\t\t\tmut is_large := field.expr.val.len > 13\n\t\t\t\tif !is_large && field.expr.val.len > 8 {\n\t\t\t\t\tval := field.expr.val.i64()\n\t\t\t\t\tis_large = val > checker.int_max || val < checker.int_min\n\t\t\t\t}\n\t\t\t\tif is_large {\n\t\t\t\t\tc.error('overflow in implicit type `int`, use explicit type casting instead',\n\t\t\t\t\t\tfield.expr.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tc.const_deps = []\n\t\tc.const_var = prev_const_var\n\t}\n}\n\nfn (mut c Checker) enum_decl(mut node ast.EnumDecl) {\n\tc.check_valid_pascal_case(node.name, 'enum name', node.pos)\n\tmut useen := []u64{}\n\tmut iseen := []i64{}\n\tmut seen_enum_field_names := map[string]int{}\n\tif node.fields.len == 0 {\n\t\tc.error('enum cannot be empty', node.pos)\n\t}\n\t/*\n\tif node.is_pub && c.mod == 'builtin' {\n\t\tc.error('`builtin` module cannot have enums', node.pos)\n\t}\n\t*/\n\tmut enum_imin := i64(0)\n\tmut enum_imax := i64(0)\n\tmut enum_umin := u64(0)\n\tmut enum_umax := u64(0)\n\tmut signed := true\n\tsenum_type := c.table.type_to_str(node.typ)\n\tmatch node.typ {\n\t\tast.i8_type {\n\t\t\tsigned, enum_imin, enum_imax = true, min_i8, max_i8\n\t\t}\n\t\tast.i16_type {\n\t\t\tsigned, enum_imin, enum_imax = true, min_i16, max_i16\n\t\t}\n\t\tast.int_type {\n\t\t\tsigned, enum_imin, enum_imax = true, min_i32, max_i32\n\t\t}\n\t\tast.i64_type {\n\t\t\tsigned, enum_imin, enum_imax = true, min_i64, max_i64\n\t\t}\n\t\t//\n\t\tast.u8_type {\n\t\t\tsigned, enum_umin, enum_umax = false, min_u8, max_u8\n\t\t}\n\t\tast.u16_type {\n\t\t\tsigned, enum_umin, enum_umax = false, min_u16, max_u16\n\t\t}\n\t\tast.u32_type {\n\t\t\tsigned, enum_umin, enum_umax = false, min_u32, max_u32\n\t\t}\n\t\tast.u64_type {\n\t\t\tsigned, enum_umin, enum_umax = false, min_u64, max_u64\n\t\t}\n\t\telse {\n\t\t\tif senum_type == 'i32' {\n\t\t\t\tsigned, enum_imin, enum_imax = true, min_i32, max_i32\n\t\t\t} else {\n\t\t\t\tc.error('`${senum_type}` is not one of `i8`,`i16`,`i32`,`int`,`i64`,`u8`,`u16`,`u32`,`u64`',\n\t\t\t\t\tnode.typ_pos)\n\t\t\t}\n\t\t}\n\t}\n\tif enum_imin > 0 {\n\t\t// ensure that the minimum value is negative, even with msvc, which has a bug that makes -2147483648 positive ...\n\t\tenum_imin *= -1\n\t}\n\tfor i, mut field in node.fields {\n\t\tif !c.pref.experimental && util.contains_capital(field.name) {\n\t\t\t// TODO C2V uses hundreds of enums with capitals, remove -experimental check once it's handled\n\t\t\tc.error('field name `${field.name}` cannot contain uppercase letters, use snake_case instead',\n\t\t\t\tfield.pos)\n\t\t}\n\t\tif _ := seen_enum_field_names[field.name] {\n\t\t\tc.error('duplicate enum field name `${field.name}`', field.pos)\n\t\t}\n\t\tseen_enum_field_names[field.name] = i\n\t\tif field.has_expr {\n\t\t\tmatch mut field.expr {\n\t\t\t\tast.IntegerLiteral {\n\t\t\t\t\tc.check_enum_field_integer_literal(field.expr, signed, node.is_multi_allowed,\n\t\t\t\t\t\tsenum_type, field.expr.pos, mut useen, enum_umin, enum_umax, mut\n\t\t\t\t\t\tiseen, enum_imin, enum_imax)\n\t\t\t\t}\n\t\t\t\tast.InfixExpr {\n\t\t\t\t\t// Handle `enum Foo { x = 1 + 2 }`\n\t\t\t\t\tc.infix_expr(mut field.expr)\n\t\t\t\t\tmut t := transformer.new_transformer_with_table(c.table, c.pref)\n\t\t\t\t\tfolded_expr := t.infix_expr(mut field.expr)\n\n\t\t\t\t\tif folded_expr is ast.IntegerLiteral {\n\t\t\t\t\t\tc.check_enum_field_integer_literal(folded_expr, signed, node.is_multi_allowed,\n\t\t\t\t\t\t\tsenum_type, field.expr.pos, mut useen, enum_umin, enum_umax, mut\n\t\t\t\t\t\t\tiseen, enum_imin, enum_imax)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tast.ParExpr {\n\t\t\t\t\tc.expr(mut field.expr.expr)\n\t\t\t\t\tmut t := transformer.new_transformer_with_table(c.table, c.pref)\n\t\t\t\t\tfolded_expr := t.expr(mut field.expr.expr)\n\n\t\t\t\t\tif folded_expr is ast.IntegerLiteral {\n\t\t\t\t\t\tc.check_enum_field_integer_literal(folded_expr, signed, node.is_multi_allowed,\n\t\t\t\t\t\t\tsenum_type, field.expr.pos, mut useen, enum_umin, enum_umax, mut\n\t\t\t\t\t\t\tiseen, enum_imin, enum_imax)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tast.CastExpr {\n\t\t\t\t\tfe_type := c.cast_expr(mut field.expr)\n\t\t\t\t\tif node.typ != fe_type {\n\t\t\t\t\t\tsfe_type := c.table.type_to_str(fe_type)\n\t\t\t\t\t\tc.error('the type of the enum value `${sfe_type}` != the enum type itself `${senum_type}`',\n\t\t\t\t\t\t\tfield.expr.pos)\n\t\t\t\t\t}\n\t\t\t\t\tif !fe_type.is_pure_int() {\n\t\t\t\t\t\tc.error('the type of an enum value must be an integer type, like i8, u8, int, u64 etc.',\n\t\t\t\t\t\t\tfield.expr.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif mut field.expr is ast.Ident {\n\t\t\t\t\t\tif field.expr.language == .c {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif field.expr.kind == .unresolved {\n\t\t\t\t\t\t\tc.ident(mut field.expr)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif field.expr.kind == .constant && field.expr.obj.typ.is_int() {\n\t\t\t\t\t\t\t// accepts int constants as enum value\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmut pos := field.expr.pos()\n\t\t\t\t\tif pos.pos == 0 {\n\t\t\t\t\t\tpos = field.pos\n\t\t\t\t\t}\n\t\t\t\t\tc.error('the default value for an enum has to be an integer', pos)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif signed {\n\t\t\t\tif iseen.len > 0 {\n\t\t\t\t\tilast := iseen.last()\n\t\t\t\t\tif ilast == enum_imax {\n\t\t\t\t\t\tc.error('enum value overflows type `${senum_type}`, which has a maximum value of ${enum_imax}',\n\t\t\t\t\t\t\tfield.pos)\n\t\t\t\t\t} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed\n\t\t\t\t\t\t&& ilast + 1 in iseen {\n\t\t\t\t\t\tc.error('enum value `${ilast + 1}` already exists', field.pos)\n\t\t\t\t\t}\n\t\t\t\t\tiseen << ilast + 1\n\t\t\t\t} else {\n\t\t\t\t\tiseen << 0\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif useen.len > 0 {\n\t\t\t\t\tulast := useen.last()\n\t\t\t\t\tif ulast == enum_umax {\n\t\t\t\t\t\tc.error('enum value overflows type `${senum_type}`, which has a maximum value of ${enum_umax}',\n\t\t\t\t\t\t\tfield.pos)\n\t\t\t\t\t} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed\n\t\t\t\t\t\t&& ulast + 1 in useen {\n\t\t\t\t\t\tc.error('enum value `${ulast + 1}` already exists', field.pos)\n\t\t\t\t\t}\n\t\t\t\t\tuseen << ulast + 1\n\t\t\t\t} else {\n\t\t\t\t\tuseen << 0\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn (mut c Checker) check_enum_field_integer_literal(expr ast.IntegerLiteral, is_signed bool, is_multi_allowed bool, styp string, pos token.Pos, mut useen []u64, umin u64, umax u64, mut iseen []i64, imin i64, imax i64) {\n\tmut overflows := false\n\tmut uval := u64(0)\n\tmut ival := i64(0)\n\n\tif is_signed {\n\t\tval := expr.val.i64()\n\t\tival = val\n\t\tif val < imin || val >= imax {\n\t\t\tc.error('enum value `${expr.val}` overflows the enum type `${styp}`, values of which have to be in [${imin}, ${imax}]',\n\t\t\t\tpos)\n\t\t\toverflows = true\n\t\t}\n\t} else {\n\t\tval := expr.val.u64()\n\t\tuval = val\n\t\tif val >= umax {\n\t\t\toverflows = true\n\t\t\tif val == umax {\n\t\t\t\tis_bin := expr.val.starts_with('0b')\n\t\t\t\tis_oct := expr.val.starts_with('0o')\n\t\t\t\tis_hex := expr.val.starts_with('0x')\n\n\t\t\t\tif is_hex {\n\t\t\t\t\toverflows = val.hex() != umax.hex()\n\t\t\t\t} else if !is_bin && !is_oct && !is_hex {\n\t\t\t\t\toverflows = expr.val.str() != umax.str()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif overflows {\n\t\t\t\tc.error('enum value `${expr.val}` overflows the enum type `${styp}`, values of which have to be in [${umin}, ${umax}]',\n\t\t\t\t\tpos)\n\t\t\t}\n\t\t}\n\t}\n\tif !overflows && !c.pref.translated && !c.file.is_translated && !is_multi_allowed {\n\t\tif (is_signed && ival in iseen) || (!is_signed && uval in useen) {\n\t\t\tc.error('enum value `${expr.val}` already exists', pos)\n\t\t}\n\t}\n\tif is_signed {\n\t\tiseen << ival\n\t} else {\n\t\tuseen << uval\n\t}\n}\n\n@[inline]\nfn (mut c Checker) check_loop_label(label string, pos token.Pos) {\n\tif label.len == 0 {\n\t\t// ignore\n\t\treturn\n\t}\n\tif c.loop_label.len != 0 {\n\t\tc.error('nesting of labelled `for` loops is not supported', pos)\n\t\treturn\n\t}\n\tc.loop_label = label\n}\n\nfn (mut c Checker) stmt(mut node ast.Stmt) {\n\t$if trace_checker ? {\n\t\tntype := typeof(*node).replace('v.ast.', '')\n\t\teprintln('checking: ${c.file.path:-30} | pos: ${node.pos.line_str():-39} | node: ${ntype} | ${node}')\n\t}\n\tc.expected_type = ast.void_type\n\tmatch mut node {\n\t\tast.EmptyStmt {\n\t\t\tif c.pref.is_verbose {\n\t\t\t\teprintln('Checker.stmt() EmptyStmt')\n\t\t\t\tprint_backtrace()\n\t\t\t}\n\t\t}\n\t\tast.NodeError {}\n\t\tast.DebuggerStmt {}\n\t\tast.AsmStmt {\n\t\t\tc.asm_stmt(mut node)\n\t\t}\n\t\tast.AssertStmt {\n\t\t\tc.assert_stmt(mut node)\n\t\t}\n\t\tast.AssignStmt {\n\t\t\tc.assign_stmt(mut node)\n\t\t}\n\t\tast.Block {\n\t\t\tc.block(mut node)\n\t\t}\n\t\tast.BranchStmt {\n\t\t\tc.branch_stmt(node)\n\t\t}\n\t\tast.ComptimeFor {\n\t\t\tc.comptime_for(mut node)\n\t\t}\n\t\tast.ConstDecl {\n\t\t\tc.inside_const = true\n\t\t\tc.const_decl(mut node)\n\t\t\tc.inside_const = false\n\t\t}\n\t\tast.DeferStmt {\n\t\t\tif node.idx_in_fn < 0 && c.table.cur_fn != unsafe { nil } {\n\t\t\t\tnode.idx_in_fn = c.table.cur_fn.defer_stmts.len\n\t\t\t\tc.table.cur_fn.defer_stmts << unsafe { &node }\n\t\t\t}\n\t\t\tif c.locked_names.len != 0 || c.rlocked_names.len != 0 {\n\t\t\t\tc.error('defers are not allowed in lock statements', node.pos)\n\t\t\t}\n\t\t\tfor i, ident in node.defer_vars {\n\t\t\t\tmut id := ident\n\t\t\t\tif mut id.info is ast.IdentVar {\n\t\t\t\t\tif id.comptime && (id.tok_kind == .question\n\t\t\t\t\t\t|| id.name in ast.valid_comptime_not_user_defined) {\n\t\t\t\t\t\tnode.defer_vars[i] = ast.Ident{\n\t\t\t\t\t\t\tscope: unsafe { nil }\n\t\t\t\t\t\t\tname: ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\ttyp := c.ident(mut id)\n\t\t\t\t\tif typ == ast.error_type_idx {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tid.info.typ = typ\n\t\t\t\t\tnode.defer_vars[i] = id\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.inside_defer = true\n\t\t\tc.stmts(mut node.stmts)\n\t\t\tc.inside_defer = false\n\t\t}\n\t\tast.EnumDecl {\n\t\t\tc.enum_decl(mut node)\n\t\t}\n\t\tast.ExprStmt {\n\t\t\tnode.typ = c.expr(mut node.expr)\n\t\t\tc.expected_type = ast.void_type\n\t\t\tmut or_typ := ast.void_type\n\t\t\tmatch mut node.expr {\n\t\t\t\tast.IndexExpr {\n\t\t\t\t\tif node.expr.or_expr.kind != .absent {\n\t\t\t\t\t\tnode.is_expr = true\n\t\t\t\t\t\tor_typ = node.typ\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tast.PrefixExpr {\n\t\t\t\t\tif node.expr.or_block.kind != .absent {\n\t\t\t\t\t\tnode.is_expr = true\n\t\t\t\t\t\tor_typ = node.typ\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t\tif !c.pref.is_repl && (c.stmt_level == 1 || (c.stmt_level > 1 && !c.is_last_stmt)) {\n\t\t\t\tif mut node.expr is ast.InfixExpr {\n\t\t\t\t\tif node.expr.op == .left_shift {\n\t\t\t\t\t\tleft_sym := c.table.final_sym(node.expr.left_type)\n\t\t\t\t\t\tif left_sym.kind != .array\n\t\t\t\t\t\t\t&& c.table.final_sym(c.unwrap_generic(node.expr.left_type)).kind != .array {\n\t\t\t\t\t\t\tc.error('unused expression', node.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.check_expr_option_or_result_call(node.expr, or_typ)\n\t\t\t// TODO This should work, even if it's prolly useless .-.\n\t\t\t// node.typ = c.check_expr_option_or_result_call(node.expr, ast.void_type)\n\t\t}\n\t\tast.FnDecl {\n\t\t\tc.fn_decl(mut node)\n\t\t}\n\t\tast.ForCStmt {\n\t\t\tc.for_c_stmt(mut node)\n\t\t}\n\t\tast.ForInStmt {\n\t\t\tc.for_in_stmt(mut node)\n\t\t}\n\t\tast.ForStmt {\n\t\t\tc.for_stmt(mut node)\n\t\t}\n\t\tast.GlobalDecl {\n\t\t\tc.global_decl(mut node)\n\t\t}\n\t\tast.GotoLabel {\n\t\t\tc.goto_label(node)\n\t\t}\n\t\tast.GotoStmt {\n\t\t\tc.goto_stmt(node)\n\t\t}\n\t\tast.HashStmt {\n\t\t\tc.hash_stmt(mut node)\n\t\t}\n\t\tast.Import {\n\t\t\tc.import_stmt(node)\n\t\t}\n\t\tast.InterfaceDecl {\n\t\t\tc.interface_decl(mut node)\n\t\t}\n\t\tast.Module {\n\t\t\tc.mod = node.name\n\t\t\tc.is_just_builtin_mod = node.name == 'builtin'\n\t\t\tc.is_builtin_mod = c.is_just_builtin_mod || node.name in ['os', 'strconv']\n\t\t\tc.check_valid_snake_case(node.name, 'module name', node.pos)\n\t\t}\n\t\tast.Return {\n\t\t\t// c.returns = true\n\t\t\tc.return_stmt(mut node)\n\t\t\tc.scope_returns = true\n\t\t}\n\t\tast.SemicolonStmt {}\n\t\tast.SqlStmt {\n\t\t\tc.sql_stmt(mut node)\n\t\t}\n\t\tast.StructDecl {\n\t\t\tc.struct_decl(mut node)\n\t\t}\n\t\tast.TypeDecl {\n\t\t\tc.type_decl(node)\n\t\t}\n\t}\n}\n\nfn (mut c Checker) assert_stmt(mut node ast.AssertStmt) {\n\tcur_exp_typ := c.expected_type\n\tc.expected_type = ast.bool_type\n\tassert_type := c.check_expr_option_or_result_call(node.expr, c.expr(mut node.expr))\n\tif assert_type != ast.bool_type_idx {\n\t\tatype_name := c.table.sym(assert_type).name\n\t\tc.error('assert can be used only with `bool` expressions, but found `${atype_name}` instead',\n\t\t\tnode.pos)\n\t}\n\tif node.extra !is ast.EmptyExpr {\n\t\textra_type := c.expr(mut node.extra)\n\t\tif extra_type != ast.string_type {\n\t\t\textra_type_name := c.table.sym(extra_type).name\n\t\t\tc.error('assert allows only a single string as its second argument, but found `${extra_type_name}` instead',\n\t\t\t\tnode.extra_pos)\n\t\t}\n\t}\n\tc.fail_if_unreadable(node.expr, ast.bool_type_idx, 'assertion')\n\tc.expected_type = cur_exp_typ\n}\n\nfn (mut c Checker) block(mut node ast.Block) {\n\tif node.is_unsafe {\n\t\tprev_unsafe := c.inside_unsafe\n\t\tc.inside_unsafe = true\n\t\tc.stmts(mut node.stmts)\n\t\tc.inside_unsafe = prev_unsafe\n\t} else {\n\t\tc.stmts(mut node.stmts)\n\t}\n}\n\nfn (mut c Checker) branch_stmt(node ast.BranchStmt) {\n\tif c.inside_defer {\n\t\tc.error('`${node.kind.str()}` is not allowed in defer statements', node.pos)\n\t}\n\tif c.in_for_count == 0 {\n\t\tif c.comptime.inside_comptime_for {\n\t\t\tc.error('${node.kind.str()} is not allowed within a compile-time loop', node.pos)\n\t\t} else {\n\t\t\tc.error('${node.kind.str()} statement not within a loop', node.pos)\n\t\t}\n\t}\n\tif node.label.len > 0 {\n\t\tif node.label != c.loop_label {\n\t\t\tc.error('invalid label name `${node.label}`', node.pos)\n\t\t}\n\t}\n}\n\nfn (mut c Checker) global_decl(mut node ast.GlobalDecl) {\n\tfor mut field in node.fields {\n\t\tc.check_valid_snake_case(field.name, 'global name', field.pos)\n\t\tif field.name in c.global_names {\n\t\t\tc.error('duplicate global `${field.name}`', field.pos)\n\t\t}\n\t\tif '${c.mod}.${field.name}' in c.const_names {\n\t\t\tc.error('duplicate global and const `${field.name}`', field.pos)\n\t\t}\n\t\tsym := c.table.sym(field.typ)\n\t\tif sym.kind == .placeholder {\n\t\t\tc.error('unknown type `${sym.name}`', field.typ_pos)\n\t\t}\n\t\tif field.has_expr {\n\t\t\tif field.expr is ast.AnonFn && field.name == 'main' {\n\t\t\t\tc.error('the `main` function is the program entry point, cannot redefine it',\n\t\t\t\t\tfield.pos)\n\t\t\t}\n\t\t\tfield.typ = c.expr(mut field.expr)\n\t\t\tmut v := c.file.global_scope.find_global(field.name) or {\n\t\t\t\tpanic('internal compiler error - could not find global in scope')\n\t\t\t}\n\t\t\tv.typ = ast.mktyp(field.typ)\n\t\t}\n\t\tc.global_names << field.name\n\t}\n}\n\nfn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {\n\tif stmt.is_goto {\n\t\tc.warn('inline assembly goto is not supported, it will most likely not work',\n\t\t\tstmt.pos)\n\t}\n\tif c.pref.backend.is_js() {\n\t\tc.error('inline assembly is not supported in the js backend', stmt.pos)\n\t}\n\tif c.pref.backend == .c && c.pref.ccompiler_type == .msvc {\n\t\tc.error('msvc compiler does not support inline assembly', stmt.pos)\n\t}\n\tmut aliases := c.asm_ios(mut stmt.output, mut stmt.scope, true)\n\taliases2 := c.asm_ios(mut stmt.input, mut stmt.scope, false)\n\taliases << aliases2\n\tfor mut template in stmt.templates {\n\t\tif template.is_directive {\n\t\t\t/*\n\t\t\talign n[,value]\n\t\t\t.skip n[,value]\n\t\t\t.space n[,value]\n\t\t\t.byte value1[,...]\n\t\t\t.word value1[,...]\n\t\t\t.short value1[,...]\n\t\t\t.int value1[,...]\n\t\t\t.long value1[,...]\n\t\t\t.quad immediate_value1[,...]\n\t\t\t.globl symbol\n\t\t\t.global symbol\n\t\t\t.section section\n\t\t\t.text\n\t\t\t.data\n\t\t\t.bss\n\t\t\t.fill repeat[,size[,value]]\n\t\t\t.org n\n\t\t\t.previous\n\t\t\t.string string[,...]\n\t\t\t.asciz string[,...]\n\t\t\t.ascii string[,...]\n\t\t\t*/\n\t\t\tif template.name !in ['skip', 'space', 'byte', 'word', 'short', 'int', 'long', 'quad',\n\t\t\t\t'globl', 'global', 'section', 'text', 'data', 'bss', 'fill', 'org', 'previous',\n\t\t\t\t'string', 'asciz', 'ascii'] { // all tcc-supported assembler directives\n\t\t\t\tc.error('unknown assembler directive: `${template.name}`', template.pos)\n\t\t\t}\n\t\t}\n\t\tfor mut arg in template.args {\n\t\t\tc.asm_arg(arg, stmt, aliases)\n\t\t}\n\t}\n\tfor mut clob in stmt.clobbered {\n\t\tc.asm_arg(clob.reg, stmt, aliases)\n\t}\n}\n\nfn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {\n\tmatch arg {\n\t\tast.AsmAlias {}\n\t\tast.AsmAddressing {\n\t\t\tif arg.scale !in [-1, 1, 2, 4, 8] {\n\t\t\t\tc.error('scale must be one of 1, 2, 4, or 8', arg.pos)\n\t\t\t}\n\t\t\tc.asm_arg(arg.displacement, stmt, aliases)\n\t\t\tc.asm_arg(arg.base, stmt, aliases)\n\t\t\tc.asm_arg(arg.index, stmt, aliases)\n\t\t}\n\t\tast.BoolLiteral {} // all of these are guaranteed to be correct.\n\t\tast.FloatLiteral {}\n\t\tast.CharLiteral {}\n\t\tast.IntegerLiteral {}\n\t\tast.AsmRegister {} // if the register is not found, the parser will register it as an alias\n\t\tast.AsmDisp {}\n\t\tstring {}\n\t}\n}\n\nfn (mut c Checker) asm_ios(mut ios []ast.AsmIO, mut scope ast.Scope, output bool) []string {\n\tmut aliases := []string{}\n\tfor mut io in ios {\n\t\ttyp := c.expr(mut io.expr)\n\t\tif output {\n\t\t\tc.fail_if_immutable(mut io.expr)\n\t\t}\n\t\tif io.alias != '' {\n\t\t\taliases << io.alias\n\t\t\tif io.alias in scope.objects {\n\t\t\t\tscope.objects[io.alias] = ast.Var{\n\t\t\t\t\tname: io.alias\n\t\t\t\t\texpr: io.expr\n\t\t\t\t\tis_arg: true\n\t\t\t\t\ttyp: typ\n\t\t\t\t\torig_type: typ\n\t\t\t\t\tpos: io.pos\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn aliases\n}\n\nfn (mut c Checker) hash_stmt(mut node ast.HashStmt) {\n\tif c.skip_flags {\n\t\treturn\n\t}\n\tif c.ct_cond_stack.len > 0 {\n\t\tnode.ct_conds = c.ct_cond_stack.clone()\n\t}\n\tif c.pref.backend.is_js() || c.pref.backend == .golang {\n\t\t// consider the best way to handle the .go.vv files\n\t\tif !c.file.path.ends_with('.js.v') && !c.file.path.ends_with('.go.v')\n\t\t\t&& !c.file.path.ends_with('.go.vv') {\n\t\t\tc.error('hash statements are only allowed in backend specific files such \"x.js.v\" and \"x.go.v\"',\n\t\t\t\tnode.pos)\n\t\t}\n\t\tif c.pref.backend != .golang && c.mod == 'main' {\n\t\t\tc.error('hash statements are not allowed in the main module. Place them in a separate module.',\n\t\t\t\tnode.pos)\n\t\t}\n\t\treturn\n\t}\n\tmatch node.kind {\n\t\t'include', 'insert', 'preinclude' {\n\t\t\toriginal_flag := node.main\n\t\t\tmut flag := node.main\n\t\t\tif flag.contains('@VROOT') {\n\t\t\t\t// c.note(checker.vroot_is_deprecated_message, node.pos)\n\t\t\t\tvroot := util.resolve_vmodroot(flag.replace('@VROOT', '@VMODROOT'), c.file.path) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tnode.val = '${node.kind} ${vroot}'\n\t\t\t\tnode.main = vroot\n\t\t\t\tflag = vroot\n\t\t\t}\n\t\t\tif flag.contains('@VEXEROOT') {\n\t\t\t\tvroot := flag.replace('@VEXEROOT', os.dir(pref.vexe_path()))\n\t\t\t\tnode.val = '${node.kind} ${vroot}'\n\t\t\t\tnode.main = vroot\n\t\t\t\tflag = vroot\n\t\t\t}\n\t\t\tif flag.contains('@VMODROOT') {\n\t\t\t\tvroot := util.resolve_vmodroot(flag, c.file.path) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tnode.val = '${node.kind} ${vroot}'\n\t\t\t\tnode.main = vroot\n\t\t\t\tflag = vroot\n\t\t\t}\n\t\t\tif flag.contains('\\$env(') {\n\t\t\t\tenv := util.resolve_env_value(flag, true) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tnode.main = env\n\t\t\t}\n\t\t\tflag_no_comment := flag.all_before('//').trim_space()\n\t\t\tif node.kind == 'include' || node.kind == 'preinclude' {\n\t\t\t\tif !((flag_no_comment.starts_with('\"') && flag_no_comment.ends_with('\"'))\n\t\t\t\t\t|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {\n\t\t\t\t\tc.error('including C files should use either `\"header_file.h\"` or `<header_file.h>` quoting',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif node.kind == 'insert' {\n\t\t\t\tif !(flag_no_comment.starts_with('\"') && flag_no_comment.ends_with('\"')) {\n\t\t\t\t\tc.error('inserting .c or .h files, should use `\"header_file.h\"` quoting',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t}\n\t\t\t\tnode.main = node.main.trim('\"')\n\t\t\t\tif fcontent := os.read_file(node.main) {\n\t\t\t\t\tnode.val = fcontent\n\t\t\t\t} else {\n\t\t\t\t\tmut missing_message := 'The file ${original_flag}, needed for insertion by module `${node.mod}`,'\n\t\t\t\t\tif os.is_file(node.main) {\n\t\t\t\t\t\tmissing_message += ' is not readable.'\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmissing_message += ' does not exist.'\n\t\t\t\t\t}\n\t\t\t\t\tif node.msg != '' {\n\t\t\t\t\t\tmissing_message += ' ${node.msg}.'\n\t\t\t\t\t}\n\t\t\t\t\tc.error(missing_message, node.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t'pkgconfig' {\n\t\t\targs := if node.main.contains('--') {\n\t\t\t\tnode.main.split(' ')\n\t\t\t} else {\n\t\t\t\t'--cflags --libs ${node.main}'.split(' ')\n\t\t\t}\n\t\t\tmut m := pkgconfig.main(args) or {\n\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcflags := m.run() or {\n\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tc.table.parse_cflag(cflags, c.mod, c.pref.compile_defines_all) or {\n\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\t'flag' {\n\t\t\t// #flag linux -lm\n\t\t\tmut flag := node.main\n\t\t\tif flag == 'flag' { // Checks for empty flag\n\t\t\t\tc.error('no argument(s) provided for #flag', node.pos)\n\t\t\t}\n\t\t\tif flag.contains('@VROOT') {\n\t\t\t\t// c.note(checker.vroot_is_deprecated_message, node.pos)\n\t\t\t\tflag = util.resolve_vmodroot(flag.replace('@VROOT', '@VMODROOT'), c.file.path) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif flag.contains('@VEXEROOT') {\n\t\t\t\t// expand `@VEXEROOT` to its absolute path\n\t\t\t\tflag = flag.replace('@VEXEROOT', os.dir(pref.vexe_path()))\n\t\t\t}\n\t\t\tif flag.contains('@VMODROOT') {\n\t\t\t\tflag = util.resolve_vmodroot(flag, c.file.path) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif flag.contains('\\$env(') {\n\t\t\t\tflag = util.resolve_env_value(flag, true) or {\n\t\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] {\n\t\t\t\tif flag.contains(deprecated) {\n\t\t\t\t\tif !flag.contains('@VMODROOT') {\n\t\t\t\t\t\tc.error('${deprecated} had been deprecated, use @VMODROOT instead.',\n\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.table.parse_cflag(flag, c.mod, c.pref.compile_defines_all) or {\n\t\t\t\tc.error(err.msg(), node.pos)\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif node.kind == 'define' {\n\t\t\t\tif !c.is_builtin_mod && !c.file.path.ends_with('.c.v')\n\t\t\t\t\t&& !c.file.path.contains('vlib') {\n\t\t\t\t\tif !c.pref.is_bare {\n\t\t\t\t\t\tc.error(\"#define can only be used in vlib (V's standard library) and *.c.v files\",\n\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tc.error('expected `#define`, `#flag`, `#include`, `#insert` or `#pkgconfig` not ${node.val}',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn (mut c Checker) import_stmt(node ast.Import) {\n\tc.check_valid_snake_case(node.alias, 'module alias', node.pos)\n\tfor sym in node.syms {\n\t\tname := '${node.mod}.${sym.name}'\n\t\tif sym.name[0].is_capital() {\n\t\t\tif type_sym := c.table.find_sym(name) {\n\t\t\t\tif type_sym.kind != .placeholder {\n\t\t\t\t\tif !type_sym.is_pub {\n\t\t\t\t\t\tc.error('module `${node.mod}` type `${sym.name}` is private',\n\t\t\t\t\t\t\tsym.pos)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.error('module `${node.mod}` has no type `${sym.name}`', sym.pos)\n\t\t\tcontinue\n\t\t}\n\t\tif sym.name in ast.builtin_type_names {\n\t\t\tc.error('cannot import or override builtin type', sym.pos)\n\t\t}\n\t\tif func := c.table.find_fn(name) {\n\t\t\tif !func.is_pub {\n\t\t\t\tc.error('module `${node.mod}` function `${sym.name}()` is private', sym.pos)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif _ := c.file.global_scope.find_const(name) {\n\t\t\tcontinue\n\t\t}\n\t\tc.error('module `${node.mod}` has no constant or function `${sym.name}`', sym.pos)\n\t}\n\tif c.table.module_deprecated[node.mod] {\n\t\tc.deprecate('module', node.mod, c.table.module_attrs[node.mod], node.pos)\n\t}\n}\n\n// stmts should be used for processing normal statement lists (fn bodies, for loop bodies etc).\nfn (mut c Checker) stmts(mut stmts []ast.Stmt) {\n\told_stmt_level := c.stmt_level\n\tc.stmt_level = 0\n\tc.stmts_ending_with_expression(mut stmts)\n\tc.stmt_level = old_stmt_level\n}\n\n// stmts_ending_with_expression, should be used for processing list of statements, that can end with an expression.\n// Examples for such lists are the bodies of `or` blocks, `if` expressions and `match` expressions:\n//    `x := opt() or { stmt1 stmt2 ExprStmt }`,\n//    `x := if cond { stmt1 stmt2 ExprStmt } else { stmt2 stmt3 ExprStmt }`,\n//    `x := match expr { Type1 { stmt1 stmt2 ExprStmt } else { stmt2 stmt3 ExprStmt }`.\nfn (mut c Checker) stmts_ending_with_expression(mut stmts []ast.Stmt) {\n\tif stmts.len == 0 {\n\t\tc.scope_returns = false\n\t\treturn\n\t}\n\tif c.stmt_level > checker.stmt_level_cutoff_limit {\n\t\tc.scope_returns = false\n\t\tc.error('checker: too many stmt levels: ${c.stmt_level} ', stmts[0].pos)\n\t\treturn\n\t}\n\tmut unreachable := token.Pos{\n\t\tline_nr: -1\n\t}\n\tc.stmt_level++\n\tfor i, mut stmt in stmts {\n\t\tc.is_last_stmt = i == stmts.len - 1\n\t\tif c.scope_returns {\n\t\t\tif unreachable.line_nr == -1 {\n\t\t\t\tunreachable = stmt.pos\n\t\t\t}\n\t\t}\n\t\tc.stmt(mut stmt)\n\t\tif stmt is ast.GotoLabel {\n\t\t\tunreachable = token.Pos{\n\t\t\t\tline_nr: -1\n\t\t\t}\n\t\t\tc.scope_returns = false\n\t\t}\n\t\tif c.should_abort {\n\t\t\treturn\n\t\t}\n\t}\n\tc.stmt_level--\n\tif unreachable.line_nr >= 0 {\n\t\tc.error('unreachable code', unreachable)\n\t}\n\tc.find_unreachable_statements_after_noreturn_calls(stmts)\n\tc.scope_returns = false\n}\n\nfn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {\n\tif typ.has_flag(.generic) {\n\t\tif c.inside_generic_struct_init {\n\t\t\tgeneric_names := c.cur_struct_generic_types.map(c.table.sym(it).name)\n\t\t\tif t_typ := c.table.resolve_generic_to_concrete(typ, generic_names, c.cur_struct_concrete_types) {\n\t\t\t\treturn t_typ\n\t\t\t}\n\t\t}\n\t\tif c.table.cur_fn != unsafe { nil } {\n\t\t\tif t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,\n\t\t\t\tc.table.cur_concrete_types)\n\t\t\t{\n\t\t\t\treturn t_typ\n\t\t\t}\n\t\t}\n\t}\n\treturn typ\n}\n\npub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {\n\tc.expr_level++\n\tdefer {\n\t\tc.expr_level--\n\t}\n\n\tif c.expr_level > checker.expr_level_cutoff_limit {\n\t\tc.error('checker: too many expr levels: ${c.expr_level} ', node.pos())\n\t\treturn ast.void_type\n\t}\n\tmatch mut node {\n\t\tast.NodeError {}\n\t\tast.ComptimeType {\n\t\t\tc.error('incorrect use of compile-time type', node.pos)\n\t\t}\n\t\tast.EmptyExpr {\n\t\t\tif c.pref.is_verbose {\n\t\t\t\tprint_backtrace()\n\t\t\t}\n\t\t\tc.error('checker.expr(): unhandled EmptyExpr', token.Pos{})\n\t\t\treturn ast.void_type\n\t\t}\n\t\tast.CTempVar {\n\t\t\treturn node.typ\n\t\t}\n\t\tast.AnonFn {\n\t\t\treturn c.anon_fn(mut node)\n\t\t}\n\t\tast.ArrayDecompose {\n\t\t\ttyp := c.expr(mut node.expr)\n\t\t\ttype_sym := c.table.sym(typ)\n\t\t\tif type_sym.kind == .array_fixed {\n\t\t\t\tc.error('direct decomposition of fixed array is not allowed, convert the fixed array to normal array via ${node.expr}[..]',\n\t\t\t\t\tnode.expr.pos())\n\t\t\t\treturn ast.void_type\n\t\t\t} else if type_sym.kind != .array {\n\t\t\t\tc.error('decomposition can only be used on arrays', node.expr.pos())\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t\tarray_info := type_sym.info as ast.Array\n\t\t\telem_type := array_info.elem_type.set_flag(.variadic)\n\t\t\tnode.expr_type = typ\n\t\t\tnode.arg_type = elem_type\n\t\t\treturn elem_type\n\t\t}\n\t\tast.ArrayInit {\n\t\t\treturn c.array_init(mut node)\n\t\t}\n\t\tast.AsCast {\n\t\t\tnode.expr_type = c.expr(mut node.expr)\n\t\t\texpr_type_sym := c.table.sym(node.expr_type)\n\t\t\ttype_sym := c.table.sym(c.unwrap_generic(node.typ))\n\t\t\tif expr_type_sym.kind == .sum_type {\n\t\t\t\tc.ensure_type_exists(node.typ, node.pos)\n\t\t\t\tif !c.table.sumtype_has_variant(c.unwrap_generic(node.expr_type), c.unwrap_generic(node.typ),\n\t\t\t\t\ttrue) {\n\t\t\t\t\taddr := '&'.repeat(node.typ.nr_muls())\n\t\t\t\t\tc.error('cannot cast `${expr_type_sym.name}` to `${addr}${type_sym.name}`',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t}\n\t\t\t} else if expr_type_sym.kind == .interface_ {\n\t\t\t\tc.ensure_type_exists(node.typ, node.pos)\n\t\t\t\tif type_sym.kind != .interface_ {\n\t\t\t\t\tc.type_implements(node.typ, node.expr_type, node.pos)\n\t\t\t\t}\n\t\t\t} else if node.expr_type.clear_flag(.option) != node.typ.clear_flag(.option) {\n\t\t\t\tmut s := 'cannot cast non-sum type `${expr_type_sym.name}` using `as`'\n\t\t\t\tif type_sym.kind == .sum_type {\n\t\t\t\t\ts += ' - use e.g. `${type_sym.name}(some_expr)` instead.'\n\t\t\t\t}\n\t\t\t\tc.error(s, node.pos)\n\t\t\t}\n\t\t\treturn node.typ\n\t\t}\n\t\tast.Assoc {\n\t\t\tv := node.scope.find_var(node.var_name) or { panic(err) }\n\t\t\tfor i, _ in node.fields {\n\t\t\t\tmut expr := node.exprs[i]\n\t\t\t\tc.expr(mut expr)\n\t\t\t}\n\t\t\tnode.typ = v.typ\n\t\t\treturn v.typ\n\t\t}\n\t\tast.BoolLiteral {\n\t\t\treturn ast.bool_type\n\t\t}\n\t\tast.CastExpr {\n\t\t\treturn c.cast_expr(mut node)\n\t\t}\n\t\tast.CallExpr {\n\t\t\tmut ret_type := c.call_expr(mut node)\n\t\t\tif ret_type != 0 && c.table.sym(ret_type).kind == .alias {\n\t\t\t\tunaliased_type := c.table.unaliased_type(ret_type)\n\t\t\t\tif unaliased_type.has_option_or_result() {\n\t\t\t\t\tret_type = unaliased_type\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !ret_type.has_option_or_result() {\n\t\t\t\tc.expr_or_block_err(node.or_block.kind, node.name, node.or_block.pos,\n\t\t\t\t\tfalse)\n\t\t\t}\n\t\t\tif node.or_block.kind != .absent {\n\t\t\t\tif ret_type.has_flag(.option) {\n\t\t\t\t\tret_type = ret_type.clear_flag(.option)\n\t\t\t\t}\n\t\t\t\tif ret_type.has_flag(.result) {\n\t\t\t\t\tret_type = ret_type.clear_flag(.result)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ret_type\n\t\t}\n\t\tast.ChanInit {\n\t\t\treturn c.chan_init(mut node)\n\t\t}\n\t\tast.CharLiteral {\n\t\t\treturn ast.rune_type\n\t\t}\n\t\tast.Comment {\n\t\t\treturn ast.void_type\n\t\t}\n\t\tast.AtExpr {\n\t\t\treturn c.at_expr(mut node)\n\t\t}\n\t\tast.ComptimeCall {\n\t\t\treturn c.comptime_call(mut node)\n\t\t}\n\t\tast.ComptimeSelector {\n\t\t\treturn c.comptime_selector(mut node)\n\t\t}\n\t\tast.ConcatExpr {\n\t\t\treturn c.concat_expr(mut node)\n\t\t}\n\t\tast.DumpExpr {\n\t\t\tc.expected_type = ast.string_type\n\t\t\tnode.expr_type = c.expr(mut node.expr)\n\n\t\t\tif c.comptime.inside_comptime_for && node.expr is ast.Ident {\n\t\t\t\tif c.comptime.is_comptime_var(node.expr) {\n\t\t\t\t\tnode.expr_type = c.comptime.get_comptime_var_type(node.expr as ast.Ident)\n\t\t\t\t} else if (node.expr as ast.Ident).name in c.comptime.type_map {\n\t\t\t\t\tnode.expr_type = c.comptime.type_map[(node.expr as ast.Ident).name]\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.check_expr_option_or_result_call(node.expr, node.expr_type)\n\t\t\tetidx := node.expr_type.idx()\n\t\t\tif etidx == ast.void_type_idx {\n\t\t\t\tc.error('dump expression can not be void', node.expr.pos())\n\t\t\t\treturn ast.void_type\n\t\t\t} else if etidx == ast.char_type_idx && node.expr_type.nr_muls() == 0 {\n\t\t\t\tc.error('`char` values cannot be dumped directly, use dump(u8(x)) or dump(int(x)) instead',\n\t\t\t\t\tnode.expr.pos())\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\n\t\t\tunwrapped_expr_type := c.unwrap_generic(node.expr_type)\n\t\t\ttsym := c.table.sym(unwrapped_expr_type)\n\t\t\tif tsym.kind == .array_fixed {\n\t\t\t\tinfo := tsym.info as ast.ArrayFixed\n\t\t\t\tif !info.is_fn_ret {\n\t\t\t\t\t// for dumping fixed array we must register the fixed array struct to return from function\n\t\t\t\t\tc.table.find_or_register_array_fixed(info.elem_type, info.size, info.size_expr,\n\t\t\t\t\t\ttrue)\n\t\t\t\t}\n\t\t\t}\n\t\t\ttype_cname := if node.expr_type.has_flag(.option) {\n\t\t\t\t'_option_${tsym.cname}'\n\t\t\t} else {\n\t\t\t\ttsym.cname\n\t\t\t}\n\t\t\tc.table.dumps[int(unwrapped_expr_type.clear_flag(.result).clear_flag(.atomic_f))] = type_cname\n\t\t\tnode.cname = type_cname\n\t\t\treturn node.expr_type\n\t\t}\n\t\tast.EnumVal {\n\t\t\treturn c.enum_val(mut node)\n\t\t}\n\t\tast.FloatLiteral {\n\t\t\treturn ast.float_literal_type\n\t\t}\n\t\tast.GoExpr {\n\t\t\treturn c.go_expr(mut node)\n\t\t}\n\t\tast.SpawnExpr {\n\t\t\treturn c.spawn_expr(mut node)\n\t\t}\n\t\tast.Ident {\n\t\t\treturn c.ident(mut node)\n\t\t}\n\t\tast.IfExpr {\n\t\t\treturn c.if_expr(mut node)\n\t\t}\n\t\tast.IfGuardExpr {\n\t\t\told_inside_if_guard := c.inside_if_guard\n\t\t\tc.inside_if_guard = true\n\t\t\tnode.expr_type = c.expr(mut node.expr)\n\t\t\tc.inside_if_guard = old_inside_if_guard\n\t\t\tif !node.expr_type.has_flag(.option) && !node.expr_type.has_flag(.result) {\n\t\t\t\tmut no_opt_or_res := true\n\t\t\t\tmatch mut node.expr {\n\t\t\t\t\tast.IndexExpr {\n\t\t\t\t\t\tno_opt_or_res = false\n\t\t\t\t\t\tnode.expr_type = node.expr_type.set_flag(.option)\n\t\t\t\t\t\tnode.expr.is_option = true\n\t\t\t\t\t}\n\t\t\t\t\tast.PrefixExpr {\n\t\t\t\t\t\tif node.expr.op == .arrow {\n\t\t\t\t\t\t\tno_opt_or_res = false\n\t\t\t\t\t\t\tnode.expr_type = node.expr_type.set_flag(.option)\n\t\t\t\t\t\t\tnode.expr.is_option = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {}\n\t\t\t\t}\n\t\t\t\tif no_opt_or_res {\n\t\t\t\t\tc.error('expression should either return an Option or a Result', node.expr.pos())\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ast.bool_type\n\t\t}\n\t\tast.IndexExpr {\n\t\t\treturn c.index_expr(mut node)\n\t\t}\n\t\tast.InfixExpr {\n\t\t\treturn c.infix_expr(mut node)\n\t\t}\n\t\tast.IntegerLiteral {\n\t\t\treturn c.int_lit(mut node)\n\t\t}\n\t\tast.LambdaExpr {\n\t\t\tc.inside_lambda = true\n\t\t\tdefer {\n\t\t\t\tc.inside_lambda = false\n\t\t\t}\n\t\t\treturn c.lambda_expr(mut node, c.expected_type)\n\t\t}\n\t\tast.LockExpr {\n\t\t\treturn c.lock_expr(mut node)\n\t\t}\n\t\tast.MapInit {\n\t\t\treturn c.map_init(mut node)\n\t\t}\n\t\tast.MatchExpr {\n\t\t\treturn c.match_expr(mut node)\n\t\t}\n\t\tast.Nil {\n\t\t\tif !c.inside_unsafe {\n\t\t\t\tc.error('`nil` is only allowed in `unsafe` code', node.pos)\n\t\t\t}\n\t\t\treturn ast.nil_type\n\t\t}\n\t\tast.PostfixExpr {\n\t\t\treturn c.postfix_expr(mut node)\n\t\t}\n\t\tast.PrefixExpr {\n\t\t\treturn c.prefix_expr(mut node)\n\t\t}\n\t\tast.None {\n\t\t\treturn ast.none_type\n\t\t}\n\t\tast.OrExpr {\n\t\t\t// never happens\n\t\t\treturn ast.void_type\n\t\t}\n\t\t// ast.OrExpr2 {\n\t\t// return node.typ\n\t\t// }\n\t\tast.ParExpr {\n\t\t\tif node.expr is ast.ParExpr {\n\t\t\t\tc.warn('redundant parentheses are used', node.pos)\n\t\t\t}\n\t\t\treturn c.expr(mut node.expr)\n\t\t}\n\t\tast.RangeExpr {\n\t\t\t// branch range expression of `match x { a...b {} }`, or: `a#[x..y]`:\n\t\t\tltyp := c.expr(mut node.low)\n\t\t\thtyp := c.expr(mut node.high)\n\t\t\tif !c.check_types(ltyp, htyp) {\n\t\t\t\tlstype := c.table.type_to_str(ltyp)\n\t\t\t\thstype := c.table.type_to_str(htyp)\n\t\t\t\tc.add_error_detail('')\n\t\t\t\tc.add_error_detail(' low part type: ${lstype}')\n\t\t\t\tc.add_error_detail('high part type: ${hstype}')\n\t\t\t\tc.error('the low and high parts of a range expression, should have matching types',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t\tnode.typ = c.promote(ltyp, htyp)\n\t\t\treturn ltyp\n\t\t}\n\t\tast.SelectExpr {\n\t\t\treturn c.select_expr(mut node)\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\tmut ret_type := c.selector_expr(mut node)\n\t\t\tif c.table.sym(ret_type).kind == .chan {\n\t\t\t\treturn ret_type\n\t\t\t}\n\t\t\tif !ret_type.has_flag(.option) && !ret_type.has_flag(.result) {\n\t\t\t\tc.expr_or_block_err(node.or_block.kind, node.field_name, node.or_block.pos,\n\t\t\t\t\ttrue)\n\t\t\t}\n\t\t\tif node.or_block.kind != .absent {\n\t\t\t\tif ret_type.has_flag(.option) {\n\t\t\t\t\tret_type = ret_type.clear_flag(.option)\n\t\t\t\t}\n\t\t\t\tif ret_type.has_flag(.result) {\n\t\t\t\t\tret_type = ret_type.clear_flag(.result)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ret_type\n\t\t}\n\t\tast.SizeOf {\n\t\t\tif !node.is_type {\n\t\t\t\tnode.typ = c.expr(mut node.expr)\n\t\t\t}\n\t\t\tsym := c.table.final_sym(node.typ)\n\t\t\tif sym.kind == .placeholder && sym.language != .c {\n\t\t\t\t// Allow `sizeof(C.MYSQL_TIME)` etc\n\t\t\t\tc.error('unknown type `${sym.name}`', node.pos)\n\t\t\t}\n\t\t\t// c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type,\n\t\t\t//\tnode.typ, node.pos, 'sizeof')\n\t\t\treturn ast.u32_type\n\t\t}\n\t\tast.IsRefType {\n\t\t\tif !node.is_type {\n\t\t\t\tnode.typ = c.expr(mut node.expr)\n\t\t\t}\n\t\t\t// c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type,\n\t\t\t//\tnode.typ, node.pos, 'isreftype')\n\t\t\treturn ast.bool_type\n\t\t}\n\t\tast.OffsetOf {\n\t\t\treturn c.offset_of(node)\n\t\t}\n\t\tast.SqlExpr {\n\t\t\treturn c.sql_expr(mut node)\n\t\t}\n\t\tast.StringLiteral {\n\t\t\tif node.language == .c {\n\t\t\t\t// string literal starts with \"c\": `C.printf(c'hello')`\n\t\t\t\treturn ast.u8_type.set_nr_muls(1)\n\t\t\t}\n\t\t\treturn c.string_lit(mut node)\n\t\t}\n\t\tast.StringInterLiteral {\n\t\t\treturn c.string_inter_lit(mut node)\n\t\t}\n\t\tast.StructInit {\n\t\t\tif node.unresolved {\n\t\t\t\tmut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ))\n\t\t\t\treturn c.expr(mut expr_)\n\t\t\t}\n\t\t\tmut inited_fields := []string{}\n\t\t\treturn c.struct_init(mut node, false, mut inited_fields)\n\t\t}\n\t\tast.TypeNode {\n\t\t\tif !c.inside_x_is_type && node.typ.has_flag(.generic) && unsafe { c.table.cur_fn != 0 }\n\t\t\t\t&& c.table.cur_fn.generic_names.len == 0 {\n\t\t\t\tc.error('unexpected generic variable in non-generic function `${c.table.cur_fn.name}`',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t\treturn node.typ\n\t\t}\n\t\tast.TypeOf {\n\t\t\tif !node.is_type {\n\t\t\t\tnode.typ = c.expr(mut node.expr)\n\t\t\t}\n\t\t\treturn ast.string_type\n\t\t}\n\t\tast.UnsafeExpr {\n\t\t\treturn c.unsafe_expr(mut node)\n\t\t}\n\t\tast.Likely {\n\t\t\tltype := c.expr(mut node.expr)\n\t\t\tif !c.check_types(ltype, ast.bool_type) {\n\t\t\t\tltype_sym := c.table.sym(ltype)\n\t\t\t\tlname := if node.is_likely { '_likely_' } else { '_unlikely_' }\n\t\t\t\tc.error('`${lname}()` expects a boolean expression, instead it got `${ltype_sym.name}`',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t\treturn ast.bool_type\n\t\t}\n\t}\n\treturn ast.void_type\n}\n\n// pub fn (mut c Checker) asm_reg(mut node ast.AsmRegister) ast.Type {\n// \tname := node.name\n\n// \tfor bit_size, array in ast.x86_no_number_register_list {\n// \t\tif name in array {\n// \t\t\treturn c.table.bitsize_to_type(bit_size)\n// \t\t}\n// \t}\n// \tfor bit_size, array in ast.x86_with_number_register_list {\n// \t\tif name in array {\n// \t\t\treturn c.table.bitsize_to_type(bit_size)\n// \t\t}\n// \t}\n// \tc.error('invalid register name: `$name`', node.pos)\n// \treturn ast.void_type\n// }\n\nfn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {\n\t// Given: `Outside( Inside(xyz) )`,\n\t//        node.expr_type: `Inside`\n\t//        node.typ: `Outside`\n\tnode.expr_type = c.expr(mut node.expr) // type to be casted\n\n\tif mut node.expr is ast.ComptimeSelector {\n\t\tnode.expr_type = c.comptime.get_comptime_selector_type(node.expr, node.expr_type)\n\t}\n\n\tmut from_type := c.unwrap_generic(node.expr_type)\n\tfrom_sym := c.table.sym(from_type)\n\tfinal_from_sym := c.table.final_sym(from_type)\n\n\tmut to_type := c.unwrap_generic(node.typ)\n\tmut to_sym := c.table.sym(to_type) // type to be used as cast\n\tmut final_to_sym := c.table.final_sym(to_type)\n\tfinal_to_type := if mut to_sym.info is ast.Alias {\n\t\tto_sym.info.parent_type\n\t} else {\n\t\tto_type\n\t}\n\tfinal_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr()\n\n\tif to_type.has_flag(.result) {\n\t\tc.error('casting to Result type is forbidden', node.pos)\n\t}\n\n\tif (to_sym.is_number() && from_sym.name == 'JS.Number')\n\t\t|| (to_sym.is_number() && from_sym.name == 'JS.BigInt')\n\t\t|| (to_sym.is_string() && from_sym.name == 'JS.String')\n\t\t|| (to_type.is_bool() && from_sym.name == 'JS.Boolean')\n\t\t|| (from_type.is_bool() && to_sym.name == 'JS.Boolean')\n\t\t|| (from_sym.is_number() && to_sym.name == 'JS.Number')\n\t\t|| (from_sym.is_number() && to_sym.name == 'JS.BigInt')\n\t\t|| (from_sym.is_string() && to_sym.name == 'JS.String') {\n\t\treturn to_type\n\t}\n\n\tif to_sym.language != .c {\n\t\tc.ensure_type_exists(to_type, node.pos)\n\n\t\tif to_sym.info is ast.Alias && to_sym.info.parent_type.has_flag(.option)\n\t\t\t&& !to_type.has_flag(.option) {\n\t\t\tc.error('alias to Option type requires to be used as Option type (?${to_sym.name}(...))',\n\t\t\t\tnode.pos)\n\t\t}\n\t}\n\tif from_sym.kind == .u8 && from_type.is_ptr() && to_sym.kind == .string && !to_type.is_ptr() {\n\t\tc.error('to convert a C string buffer pointer to a V string, use x.vstring() instead of string(x)',\n\t\t\tnode.pos)\n\t}\n\tif from_type == ast.void_type {\n\t\tc.error('expression does not return a value so it cannot be cast', node.expr.pos())\n\t}\n\tif to_type.has_flag(.option) && from_type == ast.none_type {\n\t\t// allow conversion from none to every option type\n\t} else if to_sym.kind == .sum_type {\n\t\tto_sym_info := to_sym.info as ast.SumType\n\t\tif to_sym_info.generic_types.len > 0 && to_sym_info.concrete_types.len == 0 {\n\t\t\tc.error('generic sumtype `${to_sym.name}` must specify type parameter, e.g. ${to_sym.name}[int]',\n\t\t\t\tnode.pos)\n\t\t}\n\t\tif from_type in [ast.int_literal_type, ast.float_literal_type] {\n\t\t\txx := if from_type == ast.int_literal_type { ast.int_type } else { ast.f64_type }\n\t\t\tnode.expr_type = c.promote_num(node.expr_type, xx)\n\t\t\tfrom_type = node.expr_type\n\t\t}\n\t\tif !c.table.sumtype_has_variant(to_type, from_type, false) && !to_type.has_flag(.option)\n\t\t\t&& !to_type.has_flag(.result) {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\ttt := c.table.type_to_str(to_type)\n\t\t\tc.error('cannot cast `${ft}` to `${tt}`', node.pos)\n\t\t}\n\t} else if mut to_sym.info is ast.Alias && !(final_to_sym.kind == .struct_ && final_to_is_ptr) {\n\t\tif (!c.check_types(from_type, to_sym.info.parent_type) && !(final_to_sym.is_int()\n\t\t\t&& final_from_sym.kind in [.enum_, .bool, .i8, .u8, .char]))\n\t\t\t|| (final_to_sym.kind == .struct_\n\t\t\t&& from_type.idx() in [ast.voidptr_type_idx, ast.nil_type_idx]) {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\ttt := c.table.type_to_str(to_type)\n\t\t\tc.error('cannot cast `${ft}` to `${tt}` (alias to `${final_to_sym.name}`)',\n\t\t\t\tnode.pos)\n\t\t}\n\t} else if to_sym.kind == .struct_ && mut to_sym.info is ast.Struct\n\t\t&& (!to_sym.info.is_typedef || from_type.idx() in [ast.voidptr_type_idx, ast.nil_type_idx])\n\t\t&& !final_to_is_ptr {\n\t\t// For now we ignore C typedef because of `C.Window(C.None)` in vlib/clipboard (except for `from_type` is voidptr/nil)\n\t\tif from_sym.kind == .struct_ && from_sym.info is ast.Struct && !from_type.is_ptr() {\n\t\t\tif !to_type.has_flag(.option) {\n\t\t\t\tc.warn('casting to struct is deprecated, use e.g. `Struct{...expr}` instead',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t\tif !c.check_struct_signature(from_sym.info, to_sym.info) {\n\t\t\t\tc.error('cannot convert struct `${from_sym.name}` to struct `${to_sym.name}`',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t} else {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\tc.error('cannot cast `${ft}` to struct', node.pos)\n\t\t}\n\t} else if to_sym.kind == .struct_ && final_to_is_ptr {\n\t\tif from_sym.info is ast.Alias {\n\t\t\tfrom_type = from_sym.info.parent_type.derive_add_muls(from_type)\n\t\t}\n\t\tif mut node.expr is ast.IntegerLiteral {\n\t\t\tif node.expr.val.int() == 0 && !c.pref.translated && !c.file.is_translated {\n\t\t\t\tc.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })',\n\t\t\t\t\tnode.pos)\n\t\t\t} else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {\n\t\t\t\tc.error('cannot cast int to a struct pointer outside `unsafe`', node.pos)\n\t\t\t}\n\t\t} else if mut node.expr is ast.Ident {\n\t\t\tmatch mut node.expr.obj {\n\t\t\t\tast.GlobalField, ast.ConstField, ast.Var {\n\t\t\t\t\tif mut node.expr.obj.expr is ast.IntegerLiteral {\n\t\t\t\t\t\tif node.expr.obj.expr.val.int() == 0 && !c.pref.translated\n\t\t\t\t\t\t\t&& !c.file.is_translated {\n\t\t\t\t\t\t\tc.error('cannot null cast a struct pointer, use &${to_sym.name}(unsafe { nil })',\n\t\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t\t} else if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {\n\t\t\t\t\t\t\tc.error('cannot cast int to a struct pointer outside `unsafe`',\n\t\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t\tif from_type == ast.voidptr_type_idx && !c.inside_unsafe && !c.pref.translated\n\t\t\t&& !c.file.is_translated {\n\t\t\tc.error('cannot cast voidptr to a struct outside `unsafe`', node.pos)\n\t\t}\n\t\tif !from_type.is_int() && final_from_sym.kind != .enum_\n\t\t\t&& !from_type.is_any_kind_of_pointer() {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\ttt := c.table.type_to_str(to_type)\n\t\t\tc.error('cannot cast `${ft}` to `${tt}`', node.pos)\n\t\t}\n\t} else if !from_type.has_option_or_result() && mut to_sym.info is ast.Interface {\n\t\tif c.type_implements(from_type, to_type, node.pos) {\n\t\t\tif !from_type.is_any_kind_of_pointer() && from_sym.kind != .interface_\n\t\t\t\t&& !c.inside_unsafe {\n\t\t\t\tc.mark_as_referenced(mut &node.expr, true)\n\t\t\t}\n\t\t\tif to_sym.info.is_generic {\n\t\t\t\tinferred_type := c.resolve_generic_interface(from_type, to_type, node.pos)\n\t\t\t\tif inferred_type != 0 {\n\t\t\t\t\tto_type = inferred_type\n\t\t\t\t\tto_sym = c.table.sym(to_type)\n\t\t\t\t\tfinal_to_sym = c.table.final_sym(to_type)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\ttt := c.table.type_to_str(to_type)\n\t\t\tc.error('`${ft}` does not implement interface `${tt}`, cannot cast `${ft}` to interface `${tt}`',\n\t\t\t\tnode.pos)\n\t\t}\n\t} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe\n\t\t&& !c.pref.translated && !c.file.is_translated {\n\t\tc.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)\n\t} else if from_type == ast.none_type && !to_type.has_flag(.option) && !to_type.has_flag(.result) {\n\t\ttype_name := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast `none` to `${type_name}`', node.pos)\n\t} else if !from_type.has_option_or_result() && from_sym.kind == .struct_ && !from_type.is_ptr() {\n\t\tif (final_to_is_ptr || to_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {\n\t\t\tfrom_type_name := c.table.type_to_str(from_type)\n\t\t\ttype_name := c.table.type_to_str(to_type)\n\t\t\tc.error('cannot cast struct `${from_type_name}` to `${type_name}`', node.pos)\n\t\t}\n\t} else if to_sym.kind == .u8 && !final_from_sym.is_number()\n\t\t&& !from_type.is_any_kind_of_pointer() && final_from_sym.kind !in [.char, .enum_, .bool] {\n\t\tft := c.table.type_to_str(from_type)\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast type `${ft}` to `${tt}`', node.pos)\n\t} else if (from_type.has_flag(.option) && !to_type.has_flag(.option))\n\t\t|| from_type.has_flag(.result) || from_type.has_flag(.variadic) {\n\t\t// variadic case can happen when arrays are converted into variadic\n\t\tmsg := if from_type.has_flag(.option) {\n\t\t\t'an Option'\n\t\t} else if from_type.has_flag(.result) {\n\t\t\t'a Result'\n\t\t} else {\n\t\t\t'a variadic'\n\t\t}\n\t\tc.error('cannot type cast ${msg}', node.pos)\n\t} else if !c.inside_unsafe && to_type.is_ptr() && from_type.is_ptr() && to_type != from_type\n\t\t&& to_type.deref() != ast.char_type && from_type.deref() != ast.char_type {\n\t\tft := c.table.type_to_str(from_type)\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.warn('casting `${ft}` to `${tt}` is only allowed in `unsafe` code', node.pos)\n\t} else if from_sym.kind == .array_fixed && !from_type.is_ptr() {\n\t\tif !c.pref.translated && !c.file.is_translated {\n\t\t\tc.warn('cannot cast a fixed array (use e.g. `&arr[0]` instead)', node.pos)\n\t\t}\n\t} else if final_from_sym.kind == .string && final_to_sym.is_number()\n\t\t&& final_to_sym.kind != .rune {\n\t\tsnexpr := node.expr.str()\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast string to `${tt}`, use `${snexpr}.${final_to_sym.name}()` instead.',\n\t\t\tnode.pos)\n\t} else if final_from_sym.kind == .string && final_to_is_ptr && to_sym.kind != .string {\n\t\tsnexpr := node.expr.str()\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast string to `${tt}`, use `${snexpr}.str` instead.', node.pos)\n\t} else if final_from_sym.kind == .string && to_sym.kind == .char {\n\t\tsnexpr := node.expr.str()\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast string to `${tt}`, use `${snexpr}[index]` instead.', node.pos)\n\t} else if final_from_sym.kind == .string && to_type.is_voidptr()\n\t\t&& !node.expr_type.has_flag(.generic) && !from_type.is_ptr() {\n\t\tc.error('cannot cast string to `voidptr`, use voidptr(s.str) instead', node.pos)\n\t} else if final_from_sym.kind == .string && to_type.is_pointer() && !c.inside_unsafe {\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast string to `${tt}` outside `unsafe`, use ${tt}(s.str) instead',\n\t\t\tnode.pos)\n\t} else if final_from_sym.kind == .array && !from_type.is_ptr() && to_type != ast.string_type\n\t\t&& !(to_type.has_flag(.option) && from_type.idx() == to_type.idx()) {\n\t\tft := c.table.type_to_str(from_type)\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast array `${ft}` to `${tt}`', node.pos)\n\t} else if from_type.has_flag(.option) && to_type.has_flag(.option)\n\t\t&& to_sym.kind != final_from_sym.kind {\n\t\tft := c.table.type_to_str(from_type)\n\t\ttt := c.table.type_to_str(to_type)\n\t\tc.error('cannot cast incompatible option ${final_to_sym.name} `${ft}` to `${tt}`',\n\t\t\tnode.pos)\n\t}\n\n\tif to_sym.kind == .rune && from_sym.is_string() {\n\t\tsnexpr := node.expr.str()\n\t\tft := c.table.type_to_str(from_type)\n\t\tc.error('cannot cast `${ft}` to rune, use `${snexpr}.runes()` instead.', node.pos)\n\t}\n\n\tif to_sym.kind == .enum_ && !(c.inside_unsafe || c.file.is_translated) && from_sym.is_int() {\n\t\tc.error('casting numbers to enums, should be done inside `unsafe{}` blocks', node.pos)\n\t}\n\n\tif final_to_sym.kind == .function && final_from_sym.kind == .function && !(c.inside_unsafe\n\t\t|| c.file.is_translated) && !c.check_matching_function_symbols(final_from_sym, final_to_sym) {\n\t\tc.error('casting a function value from one function signature, to another function signature, should be done inside `unsafe{}` blocks',\n\t\t\tnode.pos)\n\t}\n\tif to_type.is_ptr() && to_sym.kind == .alias && from_sym.kind == .map {\n\t\tc.error('cannot cast to alias pointer `${c.table.type_to_str(to_type)}` because `${c.table.type_to_str(from_type)}` is a value',\n\t\t\tnode.pos)\n\t}\n\n\tif to_type == ast.string_type {\n\t\tif from_type in [ast.u8_type, ast.bool_type] {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\tc.error('cannot cast type `${ft}` to string, use `${snexpr}.str()` instead.',\n\t\t\t\tnode.pos)\n\t\t} else if from_type.is_any_kind_of_pointer() {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\tc.error('cannot cast pointer type `${ft}` to string, use `&u8(${snexpr}).vstring()` or `cstring_to_vstring(${snexpr})` instead.',\n\t\t\t\tnode.pos)\n\t\t} else if from_type.is_number() {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tc.error('cannot cast number to string, use `${snexpr}.str()` instead.', node.pos)\n\t\t} else if from_sym.kind == .alias && final_from_sym.name != 'string' {\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\tc.error('cannot cast type `${ft}` to string, use `x.str()` instead.', node.pos)\n\t\t} else if final_from_sym.kind == .array {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tif final_from_sym.name == '[]u8' {\n\t\t\t\tc.error('cannot cast []u8 to string, use `${snexpr}.bytestr()` or `${snexpr}.str()` instead.',\n\t\t\t\t\tnode.pos)\n\t\t\t} else {\n\t\t\t\tfirst_elem_idx := '[0]'\n\t\t\t\tc.error('cannot cast array to string, use `${snexpr}${first_elem_idx}.str()` instead.',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t} else if final_from_sym.kind == .enum_ {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tc.error('cannot cast enum to string, use ${snexpr}.str() instead.', node.pos)\n\t\t} else if final_from_sym.kind == .map {\n\t\t\tc.error('cannot cast map to string.', node.pos)\n\t\t} else if final_from_sym.kind == .sum_type {\n\t\t\tsnexpr := node.expr.str()\n\t\t\tft := c.table.type_to_str(from_type)\n\t\t\tc.error('cannot cast sumtype `${ft}` to string, use `${snexpr}.str()` instead.',\n\t\t\t\tnode.pos)\n\t\t} else if final_from_sym.kind == .function {\n\t\t\tfnexpr := node.expr.str()\n\t\t\tc.error('cannot cast function `${fnexpr}` to string', node.pos)\n\t\t} else if to_type != ast.string_type && from_type == ast.string_type\n\t\t\t&& (!(to_sym.kind == .alias && final_to_sym.name == 'string')) {\n\t\t\tmut error_msg := 'cannot cast a string to a type `${final_to_sym.name}`, that is not an alias of string'\n\t\t\tif mut node.expr is ast.StringLiteral {\n\t\t\t\tif node.expr.val.len == 1 {\n\t\t\t\t\terror_msg += \", for denoting characters use `${node.expr.val}` instead of '${node.expr.val}'\"\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.error(error_msg, node.pos)\n\t\t}\n\t} else if to_type.is_int() && mut node.expr is ast.IntegerLiteral {\n\t\ttt := c.table.type_to_str(to_type)\n\t\ttsize, _ := c.table.type_size(to_type.idx())\n\t\tbit_size := tsize * 8\n\t\tvalue_string := match node.expr.val[0] {\n\t\t\t`-`, `+` {\n\t\t\t\tnode.expr.val[1..]\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnode.expr.val\n\t\t\t}\n\t\t}\n\t\t_, e := strconv.common_parse_uint2(value_string, 0, bit_size)\n\t\tmatch e {\n\t\t\t0 {}\n\t\t\t-3 {\n\t\t\t\tc.error('value `${node.expr.val}` overflows `${tt}`', node.pos)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tc.error('cannot cast value `${node.expr.val}` to `${tt}`', node.pos)\n\t\t\t}\n\t\t}\n\t} else if to_type.is_float() && mut node.expr is ast.FloatLiteral {\n\t\ttt := c.table.type_to_str(to_type)\n\t\tstrconv.atof64(node.expr.val) or {\n\t\t\tc.error('cannot cast value `${node.expr.val}` to `${tt}`', node.pos)\n\t\t}\n\t}\n\tif from_sym.language == .v && !from_type.is_ptr()\n\t\t&& final_from_sym.kind in [.sum_type, .interface_]\n\t\t&& final_to_sym.kind !in [.sum_type, .interface_] {\n\t\tft := c.table.type_to_str(from_type)\n\t\ttt := c.table.type_to_str(to_type)\n\t\tkind_name := if from_sym.kind == .sum_type { 'sum type' } else { 'interface' }\n\t\tc.error('cannot cast `${ft}` ${kind_name} value to `${tt}`, use `${node.expr} as ${tt}` instead',\n\t\t\tnode.pos)\n\t}\n\n\tif node.has_arg {\n\t\tc.expr(mut node.arg)\n\t}\n\n\t// checks on int literal to enum cast if the value represents a value on the enum\n\tif to_sym.kind == .enum_ {\n\t\tif mut node.expr is ast.IntegerLiteral {\n\t\t\tenum_typ_name := c.table.get_type_name(to_type)\n\t\t\tnode_val := node.expr.val.i64()\n\n\t\t\tif enum_decl := c.table.enum_decls[to_sym.name] {\n\t\t\t\tmut in_range := false\n\t\t\t\tif enum_decl.is_flag {\n\t\t\t\t\t// if a flag enum has 4 variants, the maximum possible value would have all 4 flags set (0b1111)\n\t\t\t\t\tmax_val := (u64(1) << enum_decl.fields.len) - 1\n\t\t\t\t\tin_range = node_val >= 0 && u64(node_val) <= max_val\n\t\t\t\t} else {\n\t\t\t\t\tmut enum_val := i64(0)\n\n\t\t\t\t\tfor enum_field in enum_decl.fields {\n\t\t\t\t\t\t// check if the field of the enum value is an integer literal\n\t\t\t\t\t\tif enum_field.expr is ast.IntegerLiteral {\n\t\t\t\t\t\t\tenum_val = enum_field.expr.val.i64()\n\t\t\t\t\t\t} else if comptime_value := c.eval_comptime_const_expr(enum_field.expr,\n\t\t\t\t\t\t\t0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tenum_val = comptime_value.i64() or { -1 }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif node_val == enum_val {\n\t\t\t\t\t\t\tin_range = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tenum_val += 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif !in_range {\n\t\t\t\t\tc.warn('${node_val} does not represent a value of enum ${enum_typ_name}',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif node.expr_type == ast.string_type_idx {\n\t\t\tc.add_error_detail('use ${c.table.type_to_str(node.typ)}.from_string(${node.expr}) instead')\n\t\t\tc.error('cannot cast `string` to `enum`', node.pos)\n\t\t}\n\t}\n\tnode.typname = c.table.sym(node.typ).name\n\treturn node.typ\n}\n\nfn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type {\n\tmatch node.kind {\n\t\t.fn_name {\n\t\t\tif c.table.cur_fn == unsafe { nil } {\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t\tnode.val = c.table.cur_fn.name.all_after_last('.')\n\t\t}\n\t\t.method_name {\n\t\t\tif c.table.cur_fn == unsafe { nil } {\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t\tfname := c.table.cur_fn.name.all_after_last('.')\n\t\t\tif c.table.cur_fn.is_method {\n\t\t\t\tnode.val = c.table.type_to_str(c.table.cur_fn.receiver.typ).all_after_last('.') +\n\t\t\t\t\t'.' + fname\n\t\t\t} else {\n\t\t\t\tnode.val = fname\n\t\t\t}\n\t\t}\n\t\t.mod_name {\n\t\t\tif c.table.cur_fn == unsafe { nil } {\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t\tnode.val = c.table.cur_fn.mod\n\t\t}\n\t\t.struct_name {\n\t\t\tif c.table.cur_fn.is_method || c.table.cur_fn.is_static_type_method {\n\t\t\t\tnode.val = c.table.type_to_str(c.table.cur_fn.receiver.typ).all_after_last('.')\n\t\t\t} else {\n\t\t\t\tnode.val = ''\n\t\t\t}\n\t\t}\n\t\t.vexe_path {\n\t\t\tnode.val = pref.vexe_path()\n\t\t}\n\t\t.file_path {\n\t\t\tnode.val = os.real_path(c.file.path)\n\t\t}\n\t\t.line_nr {\n\t\t\tnode.val = (node.pos.line_nr + 1).str()\n\t\t}\n\t\t.file_path_line_nr {\n\t\t\tnode.val = os.file_name(c.file.path) + ':' + (node.pos.line_nr + 1).str()\n\t\t}\n\t\t.column_nr {\n\t\t\tnode.val = (node.pos.col + 1).str()\n\t\t}\n\t\t.location {\n\t\t\tmut mname := 'unknown'\n\t\t\tif c.table.cur_fn != unsafe { nil } {\n\t\t\t\tif c.table.cur_fn.is_method {\n\t\t\t\t\tmname = c.table.type_to_str(c.table.cur_fn.receiver.typ) + '{}.' +\n\t\t\t\t\t\tc.table.cur_fn.name.all_after_last('.')\n\t\t\t\t} else {\n\t\t\t\t\tmname = c.table.cur_fn.name\n\t\t\t\t}\n\t\t\t\tif c.table.cur_fn.is_static_type_method {\n\t\t\t\t\tmname = mname.replace('__static__', '.') + ' (static)'\n\t\t\t\t}\n\t\t\t}\n\t\t\tnode.val = c.file.path + ':' + (node.pos.line_nr + 1).str() + ', ${mname}'\n\t\t}\n\t\t.vhash {\n\t\t\tnode.val = version.vhash()\n\t\t}\n\t\t.v_current_hash {\n\t\t\tnode.val = c.v_current_commit_hash\n\t\t}\n\t\t.vmod_file {\n\t\t\t// cache the vmod content, do not read it many times\n\t\t\tif c.vmod_file_content.len == 0 {\n\t\t\t\tmut mcache := vmod.get_cache()\n\t\t\t\tvmod_file_location := mcache.get_by_file(c.file.path)\n\t\t\t\tif vmod_file_location.vmod_file.len == 0 {\n\t\t\t\t\tc.error('@VMOD_FILE can be used only in projects, that have v.mod file',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t}\n\t\t\t\tvmod_content := os.read_file(vmod_file_location.vmod_file) or { '' }\n\t\t\t\tc.vmod_file_content = vmod_content.replace('\\r\\n', '\\n') // normalise EOLs just in case\n\t\t\t}\n\t\t\tnode.val = c.vmod_file_content\n\t\t}\n\t\t.vroot_path {\n\t\t\tnode.val = os.dir(pref.vexe_path())\n\t\t}\n\t\t.vexeroot_path {\n\t\t\tnode.val = os.dir(pref.vexe_path())\n\t\t}\n\t\t.vmodroot_path {\n\t\t\tmut mcache := vmod.get_cache()\n\t\t\tvmod_file_location := mcache.get_by_file(c.file.path)\n\t\t\tnode.val = os.dir(vmod_file_location.vmod_file)\n\t\t}\n\t\t.unknown {\n\t\t\tc.error('unknown @ identifier: ${node.name}. Available identifiers: ${token.valid_at_tokens}',\n\t\t\t\tnode.pos)\n\t\t}\n\t}\n\treturn ast.string_type\n}\n\nstruct ACFieldMethod {\n\tname string\n\ttyp  string\n}\n\nfn (mut c Checker) ident(mut node ast.Ident) ast.Type {\n\tif c.pref.linfo.is_running {\n\t\t// Mini LS hack (v -line-info \"a.v:16\")\n\t\tc.ident_autocomplete(node)\n\t}\n\t// TODO: move this\n\tif c.const_deps.len > 0 {\n\t\tmut name := node.name\n\t\tif !name.contains('.') && node.mod != 'builtin' {\n\t\t\tname = '${node.mod}.${node.name}'\n\t\t}\n\t\t// detect cycles, while allowing for references to the same constant,\n\t\t// used inside its initialisation like: `struct Abc { x &Abc } ... const a = [ Abc{0}, Abc{unsafe{&a[0]}} ]!`\n\t\t// see vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v\n\t\tif unsafe { c.const_var != 0 } && name == c.const_var.name {\n\t\t\tif mut c.const_var.expr is ast.ArrayInit {\n\t\t\t\tif c.const_var.expr.is_fixed && c.expected_type.nr_muls() > 0 {\n\t\t\t\t\telem_typ := c.expected_type.deref()\n\t\t\t\t\tnode.kind = .constant\n\t\t\t\t\tnode.name = c.const_var.name\n\t\t\t\t\tnode.info = ast.IdentVar{\n\t\t\t\t\t\ttyp: elem_typ\n\t\t\t\t\t}\n\t\t\t\t\t// c.const_var.typ = elem_typ\n\t\t\t\t\tnode.obj = c.const_var\n\t\t\t\t\treturn c.expected_type\n\t\t\t\t}\n\t\t\t}\n\t\t\tc.error('cycle in constant `${c.const_var.name}`', node.pos)\n\t\t\treturn ast.void_type\n\t\t}\n\t\tc.const_deps << name\n\t}\n\tif node.kind == .blank_ident {\n\t\tif node.tok_kind !in [.assign, .decl_assign] {\n\t\t\tc.error('undefined ident: `_` (may only be used in assignments)', node.pos)\n\t\t}\n\t\treturn ast.void_type\n\t}\n\t// second use\n\tif node.kind in [.constant, .global, .variable] {\n\t\tinfo := node.info as ast.IdentVar\n\t\ttyp := if c.comptime.is_comptime_var(node) {\n\t\t\tctype := c.comptime.get_comptime_var_type(node)\n\t\t\tif ctype != ast.void_type {\n\t\t\t\tctype\n\t\t\t} else {\n\t\t\t\tinfo.typ\n\t\t\t}\n\t\t} else {\n\t\t\tinfo.typ\n\t\t}\n\t\t// Got a var with type T, return current generic type\n\t\tif node.or_expr.kind != .absent {\n\t\t\tif !typ.has_flag(.option) {\n\t\t\t\tif node.or_expr.kind == .propagate_option {\n\t\t\t\t\tc.error('cannot use `?` on non-option variable', node.pos)\n\t\t\t\t} else if node.or_expr.kind == .block {\n\t\t\t\t\tc.error('cannot use `or {}` block on non-option variable', node.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t\tunwrapped_typ := typ.clear_option_and_result()\n\t\t\tc.expected_or_type = unwrapped_typ\n\t\t\tc.stmts_ending_with_expression(mut node.or_expr.stmts)\n\t\t\tc.check_or_expr(node.or_expr, typ, c.expected_or_type, node)\n\t\t\treturn unwrapped_typ\n\t\t}\n\t\treturn typ\n\t} else if node.kind == .function {\n\t\tinfo := node.info as ast.IdentFn\n\t\tif func := c.table.find_fn(node.name) {\n\t\t\tif func.generic_names.len > 0 {\n\t\t\t\tconcrete_types := node.concrete_types.map(c.unwrap_generic(it))\n\t\t\t\tif concrete_types.all(!it.has_flag(.generic)) {\n\t\t\t\t\tc.table.register_fn_concrete_types(func.fkey(), concrete_types)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn info.typ\n\t} else if node.kind == .unresolved {\n\t\t// first use\n\t\tif node.tok_kind == .assign && node.is_mut {\n\t\t\tc.error('`mut` not allowed with `=` (use `:=` to declare a variable)', node.pos)\n\t\t}\n\t\tif mut obj := node.scope.find(node.name) {\n\t\t\tmatch mut obj {\n\t\t\t\tast.GlobalField {\n\t\t\t\t\tif node.mod == '' {\n\t\t\t\t\t\tnode.kind = .global\n\t\t\t\t\t\tnode.info = ast.IdentVar{\n\t\t\t\t\t\t\ttyp: obj.typ\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnode.obj = obj\n\t\t\t\t\t\treturn obj.typ\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tast.Var {\n\t\t\t\t\t// inside vweb tmpl ident positions are meaningless, use the position of the comptime call.\n\t\t\t\t\t// if the variable is declared before the comptime call then we can assume all is well.\n\t\t\t\t\t// `node.name !in node.scope.objects && node.scope.start_pos < c.comptime_call_pos` (inherited)\n\t\t\t\t\tnode_pos := if c.pref.is_vweb && node.name !in node.scope.objects\n\t\t\t\t\t\t&& node.scope.start_pos < c.comptime_call_pos {\n\t\t\t\t\t\tc.comptime_call_pos\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnode.pos.pos\n\t\t\t\t\t}\n\t\t\t\t\tif node_pos < obj.pos.pos {\n\t\t\t\t\t\tc.error('undefined variable `${node.name}` (used before declaration)',\n\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t}\n\t\t\t\t\tis_sum_type_cast := obj.smartcasts.len != 0\n\t\t\t\t\t\t&& !c.prevent_sum_type_unwrapping_once\n\t\t\t\t\tc.prevent_sum_type_unwrapping_once = false\n\t\t\t\t\tmut typ := if is_sum_type_cast { obj.smartcasts.last() } else { obj.typ }\n\t\t\t\t\tif typ == 0 {\n\t\t\t\t\t\tif mut obj.expr is ast.Ident {\n\t\t\t\t\t\t\tif obj.expr.kind == .unresolved {\n\t\t\t\t\t\t\t\tc.error('unresolved variable: `${node.name}`', node.pos)\n\t\t\t\t\t\t\t\treturn ast.void_type\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif mut obj.expr is ast.IfGuardExpr {\n\t\t\t\t\t\t\t// new variable from if guard shouldn't have the option flag for further use\n\t\t\t\t\t\t\t// a temp variable will be generated which unwraps it\n\t\t\t\t\t\t\tsym := c.table.sym(obj.expr.expr_type)\n\t\t\t\t\t\t\tif sym.kind == .multi_return {\n\t\t\t\t\t\t\t\tmr_info := sym.info as ast.MultiReturn\n\t\t\t\t\t\t\t\tif mr_info.types.len == obj.expr.vars.len {\n\t\t\t\t\t\t\t\t\tfor vi, var in obj.expr.vars {\n\t\t\t\t\t\t\t\t\t\tif var.name == node.name {\n\t\t\t\t\t\t\t\t\t\t\ttyp = mr_info.types[vi]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttyp = obj.expr.expr_type.clear_option_and_result()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if obj.expr is ast.EmptyExpr {\n\t\t\t\t\t\t\tc.error('invalid variable `${node.name}`', node.pos)\n\t\t\t\t\t\t\ttyp = ast.void_type\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttyp = c.expr(mut obj.expr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif c.inside_interface_deref && c.table.is_interface_var(obj) {\n\t\t\t\t\t\ttyp = typ.deref()\n\t\t\t\t\t}\n\t\t\t\t\tis_option := typ.has_option_or_result() || node.or_expr.kind != .absent\n\t\t\t\t\tnode.kind = .variable\n\t\t\t\t\tnode.info = ast.IdentVar{\n\t\t\t\t\t\ttyp: typ\n\t\t\t\t\t\tis_option: is_option\n\t\t\t\t\t}\n\t\t\t\t\tif !is_sum_type_cast {\n\t\t\t\t\t\tobj.typ = typ\n\t\t\t\t\t}\n\t\t\t\t\tnode.obj = obj\n\t\t\t\t\t// unwrap option (`println(x)`)\n\t\t\t\t\tif is_option {\n\t\t\t\t\t\tif node.or_expr.kind == .absent {\n\t\t\t\t\t\t\treturn typ.clear_flag(.result)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif !typ.has_flag(.option) {\n\t\t\t\t\t\t\tif node.or_expr.kind == .propagate_option {\n\t\t\t\t\t\t\t\tc.error('cannot use `?` on non-option variable', node.pos)\n\t\t\t\t\t\t\t} else if node.or_expr.kind == .block {\n\t\t\t\t\t\t\t\tc.error('cannot use `or {}` block on non-option variable',\n\t\t\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tunwrapped_typ := typ.clear_option_and_result()\n\t\t\t\t\t\tc.expected_or_type = unwrapped_typ\n\t\t\t\t\t\tc.stmts_ending_with_expression(mut node.or_expr.stmts)\n\t\t\t\t\t\tc.check_or_expr(node.or_expr, typ, c.expected_or_type, node)\n\t\t\t\t\t\treturn unwrapped_typ\n\t\t\t\t\t}\n\t\t\t\t\treturn typ\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t\tmut name := node.name\n\t\t// check for imported symbol\n\t\tif name in c.file.imported_symbols {\n\t\t\tname = c.file.imported_symbols[name]\n\t\t}\n\t\t// prepend mod to look for fn call or const\n\t\telse if !name.contains('.') && node.mod != 'builtin' {\n\t\t\tname = '${node.mod}.${node.name}'\n\t\t}\n\t\tif mut obj := c.file.global_scope.find(name) {\n\t\t\tmatch mut obj {\n\t\t\t\tast.GlobalField {\n\t\t\t\t\tnode.kind = .global\n\t\t\t\t\tnode.info = ast.IdentVar{\n\t\t\t\t\t\ttyp: obj.typ\n\t\t\t\t\t}\n\t\t\t\t\tnode.obj = obj\n\t\t\t\t\treturn obj.typ\n\t\t\t\t}\n\t\t\t\tast.ConstField {\n\t\t\t\t\tif !(obj.is_pub || obj.mod == c.mod || c.pref.is_test) {\n\t\t\t\t\t\tc.error('constant `${obj.name}` is private', node.pos)\n\t\t\t\t\t}\n\t\t\t\t\tmut typ := obj.typ\n\t\t\t\t\tif typ == 0 {\n\t\t\t\t\t\told_c_mod := c.mod\n\t\t\t\t\t\tc.mod = obj.mod\n\t\t\t\t\t\tc.inside_const = true\n\t\t\t\t\t\ttyp = c.expr(mut obj.expr)\n\t\t\t\t\t\tc.inside_const = false\n\t\t\t\t\t\tc.mod = old_c_mod\n\n\t\t\t\t\t\tif mut obj.expr is ast.CallExpr {\n\t\t\t\t\t\t\tif obj.expr.or_block.kind != .absent {\n\t\t\t\t\t\t\t\ttyp = typ.clear_option_and_result()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnode.name = name\n\t\t\t\t\tnode.kind = .constant\n\t\t\t\t\tnode.info = ast.IdentVar{\n\t\t\t\t\t\ttyp: typ\n\t\t\t\t\t}\n\t\t\t\t\tobj.typ = typ\n\t\t\t\t\tnode.obj = obj\n\n\t\t\t\t\tif obj.attrs.contains('deprecated') && obj.mod != c.mod {\n\t\t\t\t\t\tc.deprecate('const', obj.name, obj.attrs, node.pos)\n\t\t\t\t\t}\n\n\t\t\t\t\tif node.or_expr.kind != .absent {\n\t\t\t\t\t\tunwrapped_typ := typ.clear_option_and_result()\n\t\t\t\t\t\tc.expected_or_type = unwrapped_typ\n\t\t\t\t\t\tc.stmts_ending_with_expression(mut node.or_expr.stmts)\n\t\t\t\t\t\tc.check_or_expr(node.or_expr, typ, c.expected_or_type, node)\n\t\t\t\t\t}\n\t\t\t\t\treturn typ\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t\t// Non-anon-function object (not a call), e.g. `onclick(my_click)`\n\t\tif func := c.table.find_fn(name) {\n\t\t\tmut fn_type := ast.new_type(c.table.find_or_register_fn_type(func, false,\n\t\t\t\ttrue))\n\t\t\tif func.generic_names.len > 0 {\n\t\t\t\tconcrete_types := node.concrete_types.map(c.unwrap_generic(it))\n\t\t\t\tif typ_ := c.table.resolve_generic_to_concrete(fn_type, func.generic_names,\n\t\t\t\t\tconcrete_types)\n\t\t\t\t{\n\t\t\t\t\tfn_type = typ_\n\t\t\t\t\tif concrete_types.all(!it.has_flag(.generic)) {\n\t\t\t\t\t\tc.table.register_fn_concrete_types(func.fkey(), concrete_types)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnode.name = name\n\t\t\tnode.kind = .function\n\t\t\tnode.info = ast.IdentFn{\n\t\t\t\ttyp: fn_type\n\t\t\t}\n\t\t\treturn fn_type\n\t\t}\n\t}\n\tif node.language == .c {\n\t\tif node.name == 'C.NULL' {\n\t\t\treturn ast.voidptr_type\n\t\t}\n\t\treturn ast.int_type\n\t}\n\tif c.inside_sql {\n\t\tif field := c.table.find_field(c.cur_orm_ts, node.name) {\n\t\t\treturn field.typ\n\t\t}\n\t}\n\tif node.kind == .unresolved && node.mod != 'builtin' {\n\t\t// search in the `builtin` idents, for example\n\t\t// main.compare_f32 may actually be builtin.compare_f32\n\t\tsaved_mod := node.mod\n\t\tnode.mod = 'builtin'\n\t\tbuiltin_type := c.ident(mut node)\n\t\tif node.obj is ast.ConstField {\n\t\t\tfield := node.obj as ast.ConstField\n\t\t\tif field.attrs.contains('deprecated') && field.mod != c.mod {\n\t\t\t\tc.deprecate('const', field.name, field.attrs, node.pos)\n\t\t\t}\n\t\t}\n\t\tif builtin_type != ast.void_type {\n\t\t\treturn builtin_type\n\t\t}\n\t\tnode.mod = saved_mod\n\t}\n\tif node.tok_kind == .assign {\n\t\tc.error('undefined ident: `${node.name}` (use `:=` to declare a variable)', node.pos)\n\t} else if node.name == 'errcode' {\n\t\tc.error('undefined ident: `errcode`; did you mean `err.code`?', node.pos)\n\t} else {\n\t\tif c.inside_ct_attr {\n\t\t\tc.note('`[if ${node.name}]` is deprecated. Use `[if ${node.name}?]` instead',\n\t\t\t\tnode.pos)\n\t\t} else {\n\t\t\tcname_mod := node.name.all_before('.')\n\t\t\tif cname_mod.len != node.name.len {\n\t\t\t\tmut const_names_in_mod := []string{}\n\t\t\t\tfor _, so in c.table.global_scope.objects {\n\t\t\t\t\tif so is ast.ConstField {\n\t\t\t\t\t\tif so.mod == cname_mod {\n\t\t\t\t\t\t\tconst_names_in_mod << so.name\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tc.error(util.new_suggestion(node.name, const_names_in_mod).say('undefined ident: `${node.name}`'),\n\t\t\t\t\tnode.pos)\n\t\t\t} else {\n\t\t\t\t// If a variable is not found in the scope of an anonymous function\n\t\t\t\t// but is in an external scope, then we can suggest the user add it to the capturing list.\n\t\t\t\tif c.inside_anon_fn {\n\t\t\t\t\tfound_var := c.fn_scope.find_var(node.name)\n\n\t\t\t\t\tif found_var != none {\n\t\t\t\t\t\tif c.inside_lambda {\n\t\t\t\t\t\t\t// Lambdas don't support capturing variables yet, so that's the only hint.\n\t\t\t\t\t\t\tc.error('undefined variable `${node.name}`', node.pos)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tc.error('`${node.name}` must be added to the capture list for the closure to be used inside',\n\t\t\t\t\t\t\t\tnode.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn ast.void_type\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tc.error('undefined ident: `${node.name}`', node.pos)\n\t\t\t}\n\t\t}\n\t}\n\tif c.table.known_type(node.name) {\n\t\t// e.g. `User`  in `json.decode(User, '...')`\n\t\treturn ast.void_type\n\t}\n\treturn ast.void_type\n}\n\nfn (mut c Checker) concat_expr(mut node ast.ConcatExpr) ast.Type {\n\tmut mr_types := []ast.Type{}\n\tfor mut expr in node.vals {\n\t\tmr_types << c.expr(mut expr)\n\t}\n\tif node.vals.len == 1 {\n\t\ttyp := mr_types[0]\n\t\tnode.return_type = typ\n\t\treturn typ\n\t} else {\n\t\tfor i := 0; i < mr_types.len; i++ {\n\t\t\tif mr_types[i] == ast.void_type {\n\t\t\t\tc.error('type `void` cannot be used in multi-return', node.vals[i].pos())\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t}\n\t\ttyp := c.table.find_or_register_multi_return(mr_types)\n\t\tast.new_type(typ)\n\t\tnode.return_type = typ\n\t\treturn typ\n\t}\n}\n\n// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope\nfn (mut c Checker) smartcast(mut expr ast.Expr, cur_type ast.Type, to_type_ ast.Type, mut scope ast.Scope, is_comptime bool) {\n\tsym := c.table.sym(cur_type)\n\tto_type := if sym.kind == .interface_ && c.table.sym(to_type_).kind != .interface_ {\n\t\tto_type_.ref()\n\t} else {\n\t\tto_type_\n\t}\n\tmatch mut expr {\n\t\tast.SelectorExpr {\n\t\t\tmut is_mut := false\n\t\t\tmut smartcasts := []ast.Type{}\n\t\t\texpr_sym := c.table.sym(expr.expr_type)\n\t\t\tmut orig_type := 0\n\t\t\tif field := c.table.find_field(expr_sym, expr.field_name) {\n\t\t\t\tif field.is_mut {\n\t\t\t\t\tif root_ident := expr.root_ident() {\n\t\t\t\t\t\tif v := scope.find_var(root_ident.name) {\n\t\t\t\t\t\t\tis_mut = v.is_mut\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif orig_type == 0 {\n\t\t\t\t\torig_type = field.typ\n\t\t\t\t}\n\t\t\t}\n\t\t\tif field := scope.find_struct_field(expr.expr.str(), expr.expr_type, expr.field_name) {\n\t\t\t\tsmartcasts << field.smartcasts\n\t\t\t}\n\t\t\t// smartcast either if the value is immutable or if the mut argument is explicitly given\n\t\t\tif !is_mut || expr.is_mut {\n\t\t\t\tsmartcasts << to_type\n\t\t\t\tscope.register_struct_field(expr.expr.str(), ast.ScopeStructField{\n\t\t\t\t\tstruct_type: expr.expr_type\n\t\t\t\t\tname: expr.field_name\n\t\t\t\t\ttyp: cur_type\n\t\t\t\t\tsmartcasts: smartcasts\n\t\t\t\t\tpos: expr.pos\n\t\t\t\t\torig_type: orig_type\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tc.smartcast_mut_pos = expr.pos\n\t\t\t}\n\t\t}\n\t\tast.Ident {\n\t\t\tmut is_mut := false\n\t\t\tmut smartcasts := []ast.Type{}\n\t\t\tmut is_already_casted := false\n\t\t\tmut orig_type := 0\n\t\t\tmut is_inherited := false\n\t\t\tmut ct_type_var := ast.ComptimeVarKind.no_comptime\n\t\t\tif mut expr.obj is ast.Var {\n\t\t\t\tis_mut = expr.obj.is_mut\n\t\t\t\tsmartcasts << expr.obj.smartcasts\n\t\t\t\tis_already_casted = expr.obj.pos.pos == expr.pos.pos\n\t\t\t\tif orig_type == 0 {\n\t\t\t\t\torig_type = expr.obj.typ\n\t\t\t\t}\n\t\t\t\tis_inherited = expr.obj.is_inherited\n\t\t\t\tct_type_var = if is_comptime {\n\t\t\t\t\t.smartcast\n\t\t\t\t} else {\n\t\t\t\t\t.no_comptime\n\t\t\t\t}\n\t\t\t}\n\t\t\t// smartcast either if the value is immutable or if the mut argument is explicitly given\n\t\t\tif (!is_mut || expr.is_mut) && !is_already_casted {\n\t\t\t\tsmartcasts << to_type\n\t\t\t\tif var := scope.find_var(expr.name) {\n\t\t\t\t\tif is_comptime && var.ct_type_var == .smartcast {\n\t\t\t\t\t\tscope.update_smartcasts(expr.name, to_type)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscope.register(ast.Var{\n\t\t\t\t\tname: expr.name\n\t\t\t\t\ttyp: cur_type\n\t\t\t\t\tpos: expr.pos\n\t\t\t\t\tis_used: true\n\t\t\t\t\tis_mut: expr.is_mut\n\t\t\t\t\tis_inherited: is_inherited\n\t\t\t\t\tsmartcasts: smartcasts\n\t\t\t\t\torig_type: orig_type\n\t\t\t\t\tct_type_var: ct_type_var\n\t\t\t\t})\n\t\t\t} else if is_mut && !expr.is_mut {\n\t\t\t\tc.smartcast_mut_pos = expr.pos\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tc.smartcast_cond_pos = expr.pos()\n\t\t}\n\t}\n}\n\nfn (mut c Checker) select_expr(mut node ast.SelectExpr) ast.Type {\n\tnode.is_expr = c.expected_type != ast.void_type\n\tnode.expected_type = c.expected_type\n\tfor mut branch in node.branches {\n\t\tc.stmt(mut branch.stmt)\n\t\tmatch mut branch.stmt {\n\t\t\tast.ExprStmt {\n\t\t\t\tif branch.is_timeout {\n\t\t\t\t\tif !branch.stmt.typ.is_int() {\n\t\t\t\t\t\ttsym := c.table.sym(branch.stmt.typ)\n\t\t\t\t\t\tc.error('invalid type `${tsym.name}` for timeout - expected integer number of nanoseconds aka `time.Duration`',\n\t\t\t\t\t\t\tbranch.stmt.pos)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif mut branch.stmt.expr is ast.InfixExpr {\n\t\t\t\t\t\tif branch.stmt.expr.left !in [ast.Ident, ast.SelectorExpr, ast.IndexExpr] {\n\t\t\t\t\t\t\tc.error('channel in `select` key must be predefined', branch.stmt.expr.left.pos())\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc.error('invalid expression for `select` key', branch.stmt.expr.pos())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tast.AssignStmt {\n\t\t\t\texpr := branch.stmt.right[0]\n\t\t\t\tmatch expr {\n\t\t\t\t\tast.PrefixExpr {\n\t\t\t\t\t\tif expr.right !in [ast.Ident, ast.SelectorExpr, ast.IndexExpr] {\n\t\t\t\t\t\t\tc.error('channel in `select` key must be predefined', expr.right.pos())\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif expr.or_block.kind != .absent {\n\t\t\t\t\t\t\terr_prefix := if expr.or_block.kind == .block {\n\t\t\t\t\t\t\t\t'or block'\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t'error propagation'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tc.error('${err_prefix} not allowed in `select` key', expr.or_block.pos)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tc.error('`<-` receive expression expected', branch.stmt.right[0].pos())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif mut branch.stmt.left[0] is ast.Ident {\n\t\t\t\t\tident := branch.stmt.left[0] as ast.Ident\n\t\t\t\t\tif ident.kind == .blank_ident && branch.stmt.op != .decl_assign {\n\t\t\t\t\t\tc.error('cannot send on `_`, use `_ := <- quit` instead', branch.stmt.left[0].pos())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif !branch.is_else {\n\t\t\t\t\tc.error('receive or send statement expected as `select` key', branch.stmt.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tc.stmts(mut branch.stmts)\n\t}\n\treturn ast.bool_type\n}\n\nfn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {\n\texpected_type := c.expected_type\n\tif c.rlocked_names.len > 0 || c.locked_names.len > 0 {\n\t\tc.error('nested `lock`/`rlock` not allowed', node.pos)\n\t}\n\tfor i in 0 .. node.lockeds.len {\n\t\tmut expr_ := node.lockeds[i]\n\t\te_typ := c.expr(mut expr_)\n\t\tid_name := node.lockeds[i].str()\n\t\tif !e_typ.has_flag(.shared_f) {\n\t\t\tobj_type := if node.lockeds[i] is ast.Ident { 'variable' } else { 'struct element' }\n\t\t\tc.error('`${id_name}` must be declared as `shared` ${obj_type} to be locked',\n\t\t\t\tnode.lockeds[i].pos())\n\t\t}\n\t\tif id_name in c.locked_names {\n\t\t\tc.error('`${id_name}` is already locked', node.lockeds[i].pos())\n\t\t} else if id_name in c.rlocked_names {\n\t\t\tc.error('`${id_name}` is already read-locked', node.lockeds[i].pos())\n\t\t}\n\t\tif node.is_rlock[i] {\n\t\t\tc.rlocked_names << id_name\n\t\t} else {\n\t\t\tc.locked_names << id_name\n\t\t}\n\t}\n\tc.stmts(mut node.stmts)\n\t// handle `x := rlock a { a.getval() }`\n\tmut ret_type := ast.void_type\n\tif node.stmts.len > 0 {\n\t\tmut last_stmt := node.stmts.last()\n\t\tif mut last_stmt is ast.ExprStmt {\n\t\t\tc.expected_type = expected_type\n\t\t\tret_type = c.expr(mut last_stmt.expr)\n\t\t}\n\t}\n\tc.rlocked_names = []\n\tc.locked_names = []\n\tif ret_type != ast.void_type {\n\t\tnode.is_expr = true\n\t}\n\tnode.typ = ret_type\n\treturn ret_type\n}\n\nfn (mut c Checker) unsafe_expr(mut node ast.UnsafeExpr) ast.Type {\n\tprev_unsafe := c.inside_unsafe\n\tc.inside_unsafe = true\n\tt := c.expr(mut node.expr)\n\tc.inside_unsafe = prev_unsafe\n\treturn t\n}\n\nfn (mut c Checker) find_definition(ident ast.Ident) !ast.Expr {\n\tmatch ident.kind {\n\t\t.unresolved, .blank_ident { return error('none') }\n\t\t.variable, .constant { return c.find_obj_definition(ident.obj) }\n\t\t.global { return error('${ident.name} is a global variable') }\n\t\t.function { return error('${ident.name} is a function') }\n\t}\n}\n\nfn (mut c Checker) find_obj_definition(obj ast.ScopeObject) !ast.Expr {\n\t// TODO: remove once we have better type inference\n\tmut name := ''\n\tmatch obj {\n\t\tast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister { name = obj.name }\n\t}\n\tmut expr := ast.empty_expr\n\tif obj is ast.Var {\n\t\tif obj.is_mut {\n\t\t\treturn error('`${name}` is mut and may have changed since its definition')\n\t\t}\n\t\texpr = obj.expr\n\t} else if obj is ast.ConstField {\n\t\texpr = obj.expr\n\t} else {\n\t\treturn error('`${name}` is a global variable and is unknown at compile time')\n\t}\n\tif mut expr is ast.Ident {\n\t\treturn c.find_definition(expr)\n\t}\n\tif !expr.is_pure_literal() {\n\t\treturn error('definition of `${name}` is unknown at compile time')\n\t}\n\treturn expr\n}\n\nfn (c &Checker) has_return(stmts []ast.Stmt) ?bool {\n\t// complexity means either more match or ifs\n\tmut has_complexity := false\n\tfor s in stmts {\n\t\tif s is ast.ExprStmt {\n\t\t\tif s.expr in [ast.IfExpr, ast.MatchExpr] {\n\t\t\t\thas_complexity = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\t// if the inner complexity covers all paths with returns there is no need for further checks\n\tif !has_complexity || !c.returns {\n\t\treturn has_top_return(stmts)\n\t}\n\treturn none\n}\n\nfn (mut c Checker) mark_as_referenced(mut node ast.Expr, as_interface bool) {\n\tmatch mut node {\n\t\tast.Ident {\n\t\t\tif mut node.obj is ast.Var {\n\t\t\t\tmut obj := unsafe { &node.obj }\n\t\t\t\tif c.fn_scope != unsafe { nil } {\n\t\t\t\t\tobj = c.fn_scope.find_var(node.obj.name) or { obj }\n\t\t\t\t}\n\t\t\t\tif obj.typ == 0 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\ttype_sym := c.table.sym(obj.typ.set_nr_muls(0))\n\t\t\t\tif obj.is_stack_obj && !type_sym.is_heap() && !c.pref.translated\n\t\t\t\t\t&& !c.file.is_translated {\n\t\t\t\t\tsuggestion := if type_sym.kind == .struct_ {\n\t\t\t\t\t\t'declaring `${type_sym.name}` as `[heap]`'\n\t\t\t\t\t} else {\n\t\t\t\t\t\t'wrapping the `${type_sym.name}` object in a `struct` declared as `[heap]`'\n\t\t\t\t\t}\n\t\t\t\t\tmischief := if as_interface { 'used as interface object' } else { 'referenced' }\n\t\t\t\t\tc.error('`${node.name}` cannot be ${mischief} outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t} else if type_sym.kind == .array_fixed {\n\t\t\t\t\tc.error('cannot reference fixed array `${node.name}` outside `unsafe` blocks as it is supposed to be stored on stack',\n\t\t\t\t\t\tnode.pos)\n\t\t\t\t} else {\n\t\t\t\t\tmatch type_sym.kind {\n\t\t\t\t\t\t.struct_ {\n\t\t\t\t\t\t\tinfo := type_sym.info as ast.Struct\n\t\t\t\t\t\t\tif !info.is_heap {\n\t\t\t\t\t\t\t\tnode.obj.is_auto_heap = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t.sum_type, .interface_ {}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tnode.obj.is_auto_heap = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\tif !node.expr_type.is_ptr() {\n\t\t\t\tc.mark_as_referenced(mut &node.expr, as_interface)\n\t\t\t}\n\t\t}\n\t\tast.IndexExpr {\n\t\t\tc.mark_as_referenced(mut &node.left, as_interface)\n\t\t}\n\t\telse {}\n\t}\n}\n\nfn (mut c Checker) get_base_name(node &ast.Expr) string {\n\tmatch node {\n\t\tast.Ident {\n\t\t\treturn node.name\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\treturn c.get_base_name(&node.expr)\n\t\t}\n\t\tast.IndexExpr {\n\t\t\treturn c.get_base_name(&node.left)\n\t\t}\n\t\telse {\n\t\t\treturn ''\n\t\t}\n\t}\n}\n\nfn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {\n\told_inside_ref_lit := c.inside_ref_lit\n\tc.inside_ref_lit = c.inside_ref_lit || node.op == .amp\n\tright_type := c.expr(mut node.right)\n\tc.inside_ref_lit = old_inside_ref_lit\n\tnode.right_type = right_type\n\tif node.op == .amp {\n\t\tif node.right is ast.Nil {\n\t\t\tc.error('invalid operation: cannot take address of nil', node.right.pos())\n\t\t}\n\t\tif mut node.right is ast.PrefixExpr {\n\t\t\tif node.right.op == .amp {\n\t\t\t\tc.error('unexpected `&`, expecting expression', node.right.pos)\n\t\t\t}\n\t\t} else if mut node.right is ast.SelectorExpr {\n\t\t\tif node.right.expr.is_literal() {\n\t\t\t\tc.error('cannot take the address of a literal value', node.pos.extend(node.right.pos))\n\t\t\t}\n\t\t\tright_sym := c.table.sym(right_type)\n\t\t\texpr_sym := c.table.sym(node.right.expr_type)\n\t\t\tif expr_sym.kind == .struct_ && (expr_sym.info as ast.Struct).is_minify\n\t\t\t\t&& (node.right.typ == ast.bool_type_idx || (right_sym.kind == .enum_\n\t\t\t\t&& !(right_sym.info as ast.Enum).is_flag\n\t\t\t\t&& !(right_sym.info as ast.Enum).uses_exprs)) {\n\t\t\t\tc.error('cannot take the address of field in struct `${c.table.type_to_str(node.right.expr_type)}`, which is tagged as `[minify]`',\n\t\t\t\t\tnode.pos.extend(node.right.pos))\n\t\t\t}\n\n\t\t\tif node.right.typ.has_flag(.option) {\n\t\t\t\tc.error('cannot take the address of an Option field', node.pos.extend(node.right.pos))\n\t\t\t}\n\t\t}\n\t}\n\t// TODO: testing ref/deref strategy\n\tif node.op == .amp && !right_type.is_ptr() {\n\t\tmut expr := node.right\n\t\t// if ParExpr get the innermost expr\n\t\tfor mut expr is ast.ParExpr {\n\t\t\texpr = expr.expr\n\t\t}\n\t\tif expr in [ast.BoolLiteral, ast.CallExpr, ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral,\n\t\t\tast.InfixExpr, ast.StringLiteral, ast.StringInterLiteral] {\n\t\t\tc.error('cannot take the address of ${expr}', node.pos)\n\t\t}\n\t\tif mut node.right is ast.Ident {\n\t\t\tif node.right.kind == .constant && !c.inside_unsafe && c.pref.experimental {\n\t\t\t\tc.warn('cannot take the address of const outside `unsafe`', node.right.pos)\n\t\t\t}\n\t\t}\n\t\tif node.right is ast.SelectorExpr {\n\t\t\ttyp_sym := c.table.sym(right_type)\n\t\t\tif typ_sym.kind == .map && !c.inside_unsafe {\n\t\t\t\tc.error('cannot take the address of map values outside `unsafe`', node.pos)\n\t\t\t}\n\t\t}\n\t\tif mut node.right is ast.IndexExpr {\n\t\t\ttyp_sym := c.table.sym(node.right.left_type)\n\t\t\tmut is_mut := false\n\t\t\tif mut node.right.left is ast.Ident {\n\t\t\t\tident := node.right.left\n\t\t\t\t// TODO: temporary, remove this\n\t\t\t\tident_obj := ident.obj\n\t\t\t\tif ident_obj is ast.Var {\n\t\t\t\t\tis_mut = ident_obj.is_mut\n\t\t\t\t}\n\t\t\t}\n\t\t\tif typ_sym.kind == .map {\n\t\t\t\tc.error('cannot take the address of map values', node.right.pos)\n\t\t\t}\n\t\t\tif !c.inside_unsafe {\n\t\t\t\tif typ_sym.kind == .array && is_mut {\n\t\t\t\t\tc.error('cannot take the address of mutable array elements outside unsafe blocks',\n\t\t\t\t\t\tnode.right.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !c.inside_fn_arg && !c.inside_unsafe {\n\t\t\tc.mark_as_referenced(mut &node.right, false)\n\t\t}\n\t\treturn right_type.ref()\n\t} else if node.op == .amp && node.right !is ast.CastExpr {\n\t\tif !c.inside_fn_arg && !c.inside_unsafe {\n\t\t\tc.mark_as_referenced(mut &node.right, false)\n\t\t}\n\t\tif node.right.is_auto_deref_var() {\n\t\t\treturn right_type\n\t\t} else {\n\t\t\treturn right_type.ref()\n\t\t}\n\t}\n\tright_sym := c.table.final_sym(c.unwrap_generic(right_type))\n\tif node.op == .mul {\n\t\tif right_type.has_flag(.option) {\n\t\t\tc.error('type `?${right_sym.name}` is an Option, it must be unwrapped first; use `*var?` to do it',\n\t\t\t\tnode.right.pos())\n\t\t}\n\t\tif right_type.is_ptr() {\n\t\t\treturn right_type.deref()\n\t\t}\n\t\tif !right_type.is_pointer() && !c.pref.translated && !c.file.is_translated {\n\t\t\ts := c.table.type_to_str(right_type)\n\t\t\tc.error('invalid indirect of `${s}`, the type `${right_sym.name}` is not a pointer',\n\t\t\t\tnode.pos)\n\t\t}\n\t\tif right_type.is_voidptr() {\n\t\t\tc.error('cannot dereference to void', node.pos)\n\t\t}\n\t\tif mut node.right is ast.Ident {\n\t\t\tif var := node.right.scope.find_var('${node.right.name}') {\n\t\t\t\tif var.expr is ast.UnsafeExpr {\n\t\t\t\t\tif var.expr.expr is ast.Nil {\n\t\t\t\t\t\tc.error('cannot deference a `nil` pointer', node.right.pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif node.op == .bit_not && !c.pref.translated && !c.file.is_translated {\n\t\tif right_sym.info is ast.Enum && !right_sym.info.is_flag {\n\t\t\tc.error('operator `~` can only be used with `@[flag]` tagged enums', node.pos)\n\t\t}\n\t\t// Only check for int not enum as it is done above\n\t\tif !right_sym.is_int() && right_sym.info !is ast.Enum {\n\t\t\tc.type_error_for_operator('~', 'integer', right_sym.name, node.pos)\n\t\t}\n\t}\n\tif node.op == .not && right_sym.kind != .bool && !c.pref.translated && !c.file.is_translated {\n\t\tc.type_error_for_operator('!', 'bool', right_sym.name, node.pos)\n\t}\n\t// FIXME\n\t// there are currently other issues to investigate if right_type\n\t// is unwrapped directly as initialization, so do it here\n\tif node.op == .minus && !right_sym.is_number() {\n\t\tc.type_error_for_operator('-', 'numeric', right_sym.name, node.pos)\n\t}\n\tif node.op == .arrow {\n\t\traw_right_sym := c.table.final_sym(right_type)\n\t\tif raw_right_sym.kind == .chan {\n\t\t\tc.stmts_ending_with_expression(mut node.or_block.stmts)\n\t\t\treturn raw_right_sym.chan_info().elem_type\n\t\t}\n\t\tc.type_error_for_operator('<-', '`chan`', raw_right_sym.name, node.pos)\n\t}\n\treturn right_type\n}\n\nfn (mut c Checker) type_error_for_operator(op_label string, types_label string, found_type_label string, pos token.Pos) {\n\tc.error('operator `${op_label}` can only be used with ${types_label} types, but the value after `${op_label}` is of type `${found_type_label}` instead',\n\t\tpos)\n}\n\nfn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_type ast.Type, pos token.Pos, range_index bool, is_gated bool) {\n\tif typ_sym.kind in [.array, .array_fixed, .string] {\n\t\tindex_type_sym := c.table.sym(index_type)\n\t\tif !(index_type.is_int() || index_type_sym.kind == .enum_\n\t\t\t|| (index_type_sym.kind == .alias\n\t\t\t&& (index_type_sym.info as ast.Alias).parent_type.is_int())\n\t\t\t|| (c.pref.translated && index_type.is_any_kind_of_pointer())) {\n\t\t\ttype_str := if typ_sym.kind == .string {\n\t\t\t\t'non-integer string index `${c.table.type_to_str(index_type)}`'\n\t\t\t} else {\n\t\t\t\t'non-integer index `${c.table.type_to_str(index_type)}` (array type `${typ_sym.name}`)'\n\t\t\t}\n\t\t\tc.error('${type_str}', pos)\n\t\t}\n\t\tif index is ast.IntegerLiteral && !is_gated {\n\t\t\tif index.val[0] == `-` {\n\t\t\t\tc.error('negative index `${index.val}`', index.pos)\n\t\t\t} else if typ_sym.kind == .array_fixed {\n\t\t\t\ti := index.val.int()\n\t\t\t\tinfo := typ_sym.info as ast.ArrayFixed\n\t\t\t\tif (!range_index && i >= info.size) || (range_index && i > info.size) {\n\t\t\t\t\tc.error('index out of range (index: ${i}, len: ${info.size})', index.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif index_type.has_option_or_result() {\n\t\t\ttype_str := if typ_sym.kind == .string {\n\t\t\t\t'(type `${typ_sym.name}`)'\n\t\t\t} else {\n\t\t\t\t'(array type `${typ_sym.name}`)'\n\t\t\t}\n\t\t\tc.error('cannot use Option or Result as index ${type_str}', pos)\n\t\t}\n\t}\n}\n\nfn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {\n\tmut typ := c.expr(mut node.left)\n\tif typ == 0 {\n\t\tc.error('unknown type for expression `${node.left}`', node.pos)\n\t\treturn typ\n\t}\n\tmut typ_sym := c.table.final_sym(typ)\n\tnode.left_type = typ\n\tmatch typ_sym.kind {\n\t\t.map {\n\t\t\tnode.is_map = true\n\t\t}\n\t\t.array {\n\t\t\tnode.is_array = true\n\t\t\tif node.or_expr.kind != .absent && node.index is ast.RangeExpr {\n\t\t\t\tc.error('custom error handling on range expressions for arrays is not supported yet.',\n\t\t\t\t\tnode.or_expr.pos)\n\t\t\t}\n\t\t}\n\t\t.array_fixed {\n\t\t\tnode.is_farray = true\n\t\t}\n\t\t.any {\n\t\t\tunwrapped_typ := c.unwrap_generic(typ)\n\t\t\tunwrapped_sym := c.table.final_sym(unwrapped_typ)\n\t\t\tif unwrapped_sym.kind in [.map, .array, .array_fixed] {\n\t\t\t\ttyp = unwrapped_typ\n\t\t\t\ttyp_sym = unwrapped_sym\n\t\t\t}\n\t\t}\n\t\telse {}\n\t}\n\tis_aggregate_arr := typ_sym.kind == .aggregate\n\t\t&& (typ_sym.info as ast.Aggregate).types.filter(c.table.type_kind(it) !in [.array, .array_fixed, .string, .map]).len == 0\n\tif typ_sym.kind !in [.array, .array_fixed, .string, .map]\n\t\t&& (!typ.is_ptr() || typ_sym.kind in [.sum_type, .interface_])\n\t\t&& typ !in [ast.byteptr_type, ast.charptr_type] && !typ.has_flag(.variadic)\n\t\t&& !is_aggregate_arr {\n\t\tc.error('type `${typ_sym.name}` does not support indexing', node.pos)\n\t}\n\tif is_aggregate_arr {\n\t\t// treating indexexpr of sumtype of array types\n\t\ttyp = (typ_sym.info as ast.Aggregate).types[0]\n\t}\n\tif typ.has_flag(.option) {\n\t\tif node.left is ast.Ident && node.left.or_expr.kind == .absent {\n\t\t\tc.error('type `?${typ_sym.name}` is an Option, it must be unwrapped first; use `var?[]` to do it',\n\t\t\t\tnode.left.pos())\n\t\t} else if node.left is ast.CallExpr {\n\t\t\tc.error('type `?${typ_sym.name}` is an Option, it must be unwrapped with `func()?`, or use `func() or {default}`',\n\t\t\t\tnode.left.pos())\n\t\t}\n\t} else if typ.has_flag(.result) {\n\t\tc.error('type `!${typ_sym.name}` is a Result, it does not support indexing', node.left.pos())\n\t}\n\tif typ_sym.kind == .string && !typ.is_ptr() && node.is_setter {\n\t\tc.error('cannot assign to s[i] since V strings are immutable\\n' +\n\t\t\t'(note, that variables may be mutable but string values are always immutable, like in Go and Java)',\n\t\t\tnode.pos)\n\t}\n\n\tif !c.inside_unsafe && !c.is_builtin_mod && !c.inside_if_guard && !c.is_index_assign\n\t\t&& typ_sym.kind == .map && node.or_expr.stmts.len == 0 {\n\t\telem_type := c.table.value_type(typ)\n\t\tif elem_type.is_any_kind_of_pointer() {\n\t\t\tc.note('accessing a pointer map value requires an `or {}` block outside `unsafe`',\n\t\t\t\tnode.pos)\n\t\t}\n\t\tmut checked_types := []ast.Type{}\n\t\tif c.is_contains_any_kind_of_pointer(elem_type, mut checked_types) {\n\t\t\tc.note('accessing map value that contain pointers requires an `or {}` block outside `unsafe`',\n\t\t\t\tnode.pos)\n\t\t}\n\t}\n\n\tif (typ.is_ptr() && !typ.has_flag(.shared_f) && (!node.left.is_auto_deref_var()\n\t\t|| (typ_sym.kind == .struct_ && typ_sym.name != 'array')))\n\t\t|| typ.is_pointer() {\n\t\tmut is_ok := false\n\t\tmut is_mut_struct := false\n\t\tif mut node.left is ast.Ident {\n\t\t\tif mut node.left.obj is ast.Var {\n\t\t\t\t// `mut param []T` function parameter\n\t\t\t\tis_ok = node.left.obj.is_mut && node.left.obj.is_arg && !typ.deref().is_ptr()\n\t\t\t\t\t&& typ_sym.kind != .struct_\n\t\t\t\t// `mut param Struct`\n\t\t\t\tis_mut_struct = node.left.obj.is_mut && node.left.obj.is_arg\n\t\t\t\t\t&& typ_sym.kind == .struct_\n\t\t\t}\n\t\t}\n\t\tif !is_ok && node.index is ast.RangeExpr {\n\t\t\ts := c.table.type_to_str(typ)\n\t\t\tc.error('type `${s}` does not support slicing', node.pos)\n\t\t} else if is_mut_struct {\n\t\t\tc.error('type `mut ${typ_sym.name}` does not support slicing', node.pos)\n\t\t} else if !c.inside_unsafe && !is_ok && !c.pref.translated && !c.file.is_translated {\n\t\t\tc.warn('pointer indexing is only allowed in `unsafe` blocks', node.pos)\n\t\t}\n\t}\n\tif mut node.index is ast.RangeExpr { // [1..2]\n\t\tif node.index.has_low {\n\t\t\tindex_type := c.expr(mut node.index.low)\n\t\t\tc.check_index(typ_sym, node.index.low, index_type, node.pos, true, node.is_gated)\n\t\t}\n\t\tif node.index.has_high {\n\t\t\tindex_type := c.expr(mut node.index.high)\n\t\t\tc.check_index(typ_sym, node.index.high, index_type, node.pos, true, node.is_gated)\n\t\t}\n\t\t// array[1..2] => array\n\t\t// fixed_array[1..2] => array\n\t\tif typ_sym.kind == .array_fixed {\n\t\t\telem_type := c.table.value_type(typ)\n\t\t\tidx := c.table.find_or_register_array(elem_type)\n\t\t\ttyp = ast.new_type(idx)\n\t\t} else {\n\t\t\ttyp = typ.set_nr_muls(0)\n\t\t}\n\t} else { // [1]\n\t\tif typ_sym.kind == .map {\n\t\t\tinfo := typ_sym.info as ast.Map\n\t\t\tc.expected_type = info.key_type\n\t\t\tindex_type := c.expr(mut node.index)\n\t\t\tif !c.check_types(index_type, info.key_type) {\n\t\t\t\terr := c.expected_msg(index_type, info.key_type)\n\t\t\t\tc.error('invalid key: ${err}', node.pos)\n\t\t\t}\n\t\t\tvalue_sym := c.table.sym(info.value_type)\n\t\t\tif !node.is_setter && value_sym.kind == .sum_type && node.or_expr.kind == .absent\n\t\t\t\t&& !c.inside_unsafe && !c.inside_if_guard {\n\t\t\t\tc.warn('`or {}` block required when indexing a map with sum type value',\n\t\t\t\t\tnode.pos)\n\t\t\t}\n\t\t} else {\n\t\t\tindex_type := c.expr(mut node.index)\n\t\t\t// for [1] case #[1] is not allowed!\n\t\t\tif node.is_gated == true {\n\t\t\t\tc.error('`#[]` allowed only for ranges', node.pos)\n\t\t\t}\n\t\t\tc.check_index(typ_sym, node.index, index_type, node.pos, false, false)\n\t\t}\n\t\tvalue_type := c.table.value_type(typ)\n\t\tif value_type != ast.void_type {\n\t\t\ttyp = value_type\n\t\t}\n\t}\n\tif node.or_expr.stmts.len > 0 && node.or_expr.stmts.last() is ast.ExprStmt {\n\t\tc.expected_or_type = typ\n\t}\n\tc.stmts_ending_with_expression(mut node.or_expr.stmts)\n\tc.check_expr_option_or_result_call(node, typ)\n\treturn typ\n}\n\n// `.green` or `Color.green`\n// If a short form is used, `expected_type` needs to be an enum\n// with this value.\nfn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type {\n\tmut typ_idx := if node.enum_name == '' {\n\t\t// Get the type of the enum without enum name by looking at the expected type.\n\t\t// e.g. `set_color(.green)`, V knows that `Green` is the expected type.\n\t\tif c.expected_type == ast.void_type && c.expected_expr_type != ast.void_type {\n\t\t\tc.expected_expr_type.idx()\n\t\t} else {\n\t\t\tc.expected_type.idx()\n\t\t}\n\t} else {\n\t\tc.table.find_type_idx(node.enum_name)\n\t}\n\tif typ_idx == 0 {\n\t\t// Handle `builtin` enums like `ChanState`, so that `x := ChanState.closed` works.\n\t\t// In the checker the name for such enums was set to `main.ChanState` instead of\n\t\t// just `ChanState`.\n\t\tif node.enum_name.starts_with('${c.mod}.') {\n\t\t\ttyp_idx = c.table.find_type_idx(node.enum_name['${c.mod}.'.len..])\n\t\t\tif typ_idx == 0 {\n\t\t\t\tc.error('unknown enum `${node.enum_name}` (type_idx=0)', node.pos)\n\t\t\t\treturn ast.void_type\n\t\t\t}\n\t\t}\n\t\tif typ_idx == 0 {\n\t\t\t// the actual type is still unknown, produce an error, instead of panic:\n\t\t\tc.error('unknown enum `${node.enum_name}` (type_idx=0)', node.pos)\n\t\t\treturn ast.void_type\n\t\t}\n\t}\n\tmut typ := ast.new_type(typ_idx)\n\tif c.pref.translated || c.file.is_translated {\n\t\t// TODO make more strict\n\t\tnode.typ = typ\n\t\treturn typ\n\t}\n\tif typ == ast.void_type {\n\t\tc.error('not an enum', node.pos)\n\t\treturn ast.void_type\n\t}\n\tmut typ_sym := c.table.sym(typ)\n\tif typ_sym.kind == .array && node.enum_name.len == 0 {\n\t\tarray_info := typ_sym.info as ast.Array\n\t\ttyp = array_info.elem_type\n\t\ttyp_sym = c.table.sym(typ)\n\t}\n\tfsym := c.table.final_sym(typ)\n\tif fsym.kind != .enum_ && !c.pref.translated && !c.file.is_translated {\n\t\t// TODO in C int fields can be compared to enums, need to handle that in C2V\n\t\tif typ_sym.kind == .placeholder {\n\t\t\t// If it's a placeholder, the type doesn't exist, print\n\t\t\t// an error that makes sense here.\n\t\t\tc.error('unknown type `${typ_sym.name}`', node.pos)\n\t\t} else {\n\t\t\tc.error('expected type is not an enum (`${typ_sym.name}`)', node.pos)\n\t\t}\n\t\treturn ast.void_type\n\t}\n\tif fsym.info !is ast.Enum {\n\t\tc.error('not an enum', node.pos)\n\t\treturn ast.void_type\n\t}\n\tif !(typ_sym.is_pub || typ_sym.mod == c.mod) {\n\t\tc.error('enum `${typ_sym.name}` is private', node.pos)\n\t}\n\tinfo := typ_sym.enum_info()\n\tif node.val !in info.vals {\n\t\tsuggestion := util.new_suggestion(node.val, info.vals)\n\t\tc.error(suggestion.say('enum `${typ_sym.name}` does not have a value `${node.val}`'),\n\t\t\tnode.pos)\n\t}\n\tnode.typ = typ\n\treturn typ\n}\n\nfn (mut c Checker) chan_init(mut node ast.ChanInit) ast.Type {\n\tif node.typ != 0 {\n\t\tinfo := c.table.sym(node.typ).chan_info()\n\t\tnode.elem_type = info.elem_type\n\t\tif node.elem_type != 0 {\n\t\t\telem_sym := c.table.sym(node.elem_type)\n\t\t\tif elem_sym.kind == .placeholder {\n\t\t\t\tc.error('unknown type `${elem_sym.name}`', node.elem_type_pos)\n\t\t\t}\n\t\t}\n\t\tif node.has_cap {\n\t\t\tc.check_array_init_para_type('cap', mut node.cap_expr, node.pos)\n\t\t}\n\t\treturn node.typ\n\t} else {\n\t\tc.error('`chan` of unknown type', node.pos)\n\t\treturn node.typ\n\t}\n}\n\nfn (mut c Checker) offset_of(node ast.OffsetOf) ast.Type {\n\tsym := c.table.final_sym(node.struct_type)\n\tif sym.kind != .struct_ {\n\t\tc.error('first argument of __offsetof must be struct', node.pos)\n\t\treturn ast.u32_type\n\t}\n\tif !c.table.struct_has_field(sym, node.field) {\n\t\tc.error('struct `${sym.name}` has no field called `${node.field}`', node.pos)\n\t}\n\treturn ast.u32_type\n}\n\nfn (mut c Checker) check_dup_keys(node &ast.MapInit, i int) {\n\tkey_i := node.keys[i]\n\tif key_i is ast.StringLiteral {\n\t\tfor j in 0 .. i {\n\t\t\tkey_j := node.keys[j]\n\t\t\tif key_j is ast.StringLiteral {\n\t\t\t\tif key_i.val == key_j.val {\n\t\t\t\t\tc.error('duplicate key \"${key_i.val}\" in map literal', key_i.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if key_i is ast.IntegerLiteral {\n\t\tfor j in 0 .. i {\n\t\t\tkey_j := node.keys[j]\n\t\t\tif key_j is ast.IntegerLiteral {\n\t\t\t\tif key_i.val == key_j.val {\n\t\t\t\t\tc.error('duplicate key \"${key_i.val}\" in map literal', key_i.pos)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn (c &Checker) check_struct_signature_init_fields(from ast.Struct, to ast.Struct, node ast.StructInit) bool {\n\tif node.init_fields.len == 0 {\n\t\treturn from.fields.len == to.fields.len\n\t}\n\n\tmut count_not_in_from := 0\n\tfor field in node.init_fields {\n\t\tfiltered := from.fields.filter(it.name == field.name)\n\t\tif filtered.len != 1 {\n\t\t\tcount_not_in_from++\n\t\t}\n\t}\n\n\treturn (from.fields.len + count_not_in_from) == to.fields.len\n}\n\n// check `to` has all fields of `from`\nfn (c &Checker) check_struct_signature(from ast.Struct, to ast.Struct) bool {\n\t// Note: `to` can have extra fields\n\tif from.fields.len == 0 {\n\t\treturn false\n\t}\n\tfor field in from.fields {\n\t\tfiltered := to.fields.filter(it.name == field.name)\n\t\tif filtered.len != 1 {\n\t\t\t// field doesn't exist\n\t\t\treturn false\n\t\t}\n\t\tcounterpart := filtered[0]\n\t\tif field.typ != counterpart.typ {\n\t\t\t// field has different type\n\t\t\treturn false\n\t\t}\n\t\tif field.is_pub != counterpart.is_pub {\n\t\t\t// field is not public while the other one is\n\t\t\treturn false\n\t\t}\n\t\tif field.is_mut != counterpart.is_mut {\n\t\t\t// field is not mutable while the other one is\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfn (mut c Checker) fetch_field_name(field ast.StructField) string {\n\tmut name := field.name\n\tfor attr in field.attrs {\n\t\tif attr.kind == .string && attr.arg != '' && attr.name == 'sql' {\n\t\t\tname = attr.arg\n\t\t\tbreak\n\t\t}\n\t}\n\tsym := c.table.sym(field.typ)\n\tif sym.kind == .struct_ && sym.name != 'time.Time' {\n\t\tname = '${name}_id'\n\t}\n\treturn name\n}\n\nfn (mut c Checker) ensure_generic_type_specify_type_names(typ ast.Type, pos token.Pos) bool {\n\tif typ == 0 {\n\t\tc.error('unknown type', pos)\n\t\treturn false\n\t}\n\n\tc.ensure_generic_type_level++\n\tdefer {\n\t\tc.ensure_generic_type_level--\n\t}\n\tif c.ensure_generic_type_level > checker.expr_level_cutoff_limit {\n\t\tc.error('checker: too many levels of Checker.ensure_generic_type_specify_type_names calls: ${c.ensure_generic_type_level} ',\n\t\t\tpos)\n\t\treturn false\n\t}\n\n\tsym := c.table.final_sym(typ)\n\tif c.ensure_generic_type_level > 38 {\n\t\tdump(typ)\n\t\tdump(sym.kind)\n\t\tdump(pos)\n\t\tdump(c.ensure_generic_type_level)\n\t}\n\tmatch sym.kind {\n\t\t.function {\n\t\t\tfn_info := sym.info as ast.FnType\n\t\t\tif !c.ensure_generic_type_specify_type_names(fn_info.func.return_type, fn_info.func.return_type_pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfor param in fn_info.func.params {\n\t\t\t\tif !c.ensure_generic_type_specify_type_names(param.typ, param.type_pos) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.array {\n\t\t\tif !c.ensure_generic_type_specify_type_names((sym.info as ast.Array).elem_type,\n\t\t\t\tpos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.array_fixed {\n\t\t\tif !c.ensure_generic_type_specify_type_names((sym.info as ast.ArrayFixed).elem_type,\n\t\t\t\tpos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.map {\n\t\t\tinfo := sym.info as ast.Map\n\t\t\tif !c.ensure_generic_type_specify_type_names(info.key_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !c.ensure_generic_type_specify_type_names(info.value_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.sum_type {\n\t\t\tinfo := sym.info as ast.SumType\n\t\t\tif info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {\n\t\t\t\tc.error('`${sym.name}` type is generic sumtype, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',\n\t\t\t\t\tpos)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.struct_ {\n\t\t\tinfo := sym.info as ast.Struct\n\t\t\tif info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {\n\t\t\t\tc.error('`${sym.name}` type is generic struct, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',\n\t\t\t\t\tpos)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.interface_ {\n\t\t\tinfo := sym.info as ast.Interface\n\t\t\tif info.generic_types.len > 0 && !typ.has_flag(.generic) && info.concrete_types.len == 0 {\n\t\t\t\tc.error('`${sym.name}` type is generic interface, must specify the generic type names, e.g. ${sym.name}[T], ${sym.name}[int]',\n\t\t\t\t\tpos)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\telse {}\n\t}\n\treturn true\n}\n\nfn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) bool {\n\tif typ == 0 {\n\t\tc.error('unknown type', pos)\n\t\treturn false\n\t}\n\tsym := c.table.sym(typ)\n\tif !c.is_builtin_mod && sym.kind == .struct_ && !sym.is_pub && sym.mod != c.mod {\n\t\tc.error('struct `${sym.name}` was declared as private to module `${sym.mod}`, so it can not be used inside module `${c.mod}`',\n\t\t\tpos)\n\t\treturn false\n\t}\n\tmatch sym.kind {\n\t\t.placeholder {\n\t\t\t// if sym.language == .c && sym.name == 'C.time_t' {\n\t\t\t// TODO temporary hack until we can define C aliases\n\t\t\t// return true\n\t\t\t//}\n\t\t\t// if sym.language == .v && !sym.name.starts_with('C.') {\n\t\t\t// if sym.language in [.v, .c] {\n\t\t\tif sym.language == .v {\n\t\t\t\tc.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}`'),\n\t\t\t\t\tpos)\n\t\t\t\treturn false\n\t\t\t} else if sym.language == .c {\n\t\t\t\tif !c.pref.translated && !c.file.is_translated {\n\t\t\t\t\tc.warn(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `${sym.name}` (all virtual C types must be defined, this will be an error soon)'),\n\t\t\t\t\t\tpos)\n\t\t\t\t}\n\t\t\t\t// dump(sym)\n\t\t\t\t// for _, t in c.table.type_symbols {\n\t\t\t\t// println(t.name)\n\t\t\t\t//}\n\t\t\t}\n\t\t}\n\t\t.int_literal, .float_literal {\n\t\t\t// Separate error condition for `int_literal` and `float_literal` because `util.suggestion` may give different\n\t\t\t// suggestions due to f32 comparison issue.\n\t\t\tif !c.is_builtin_mod {\n\t\t\t\tmsg := if sym.kind == .int_literal {\n\t\t\t\t\t'unknown type `${sym.name}`.\\nDid you mean `int`?'\n\t\t\t\t} else {\n\t\t\t\t\t'unknown type `${sym.name}`.\\nDid you mean `f64`?'\n\t\t\t\t}\n\t\t\t\tc.error(msg, pos)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.function {\n\t\t\tfn_info := sym.info as ast.FnType\n\t\t\tif !c.ensure_type_exists(fn_info.func.return_type, fn_info.func.return_type_pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfor param in fn_info.func.params {\n\t\t\t\tif !c.ensure_type_exists(param.typ, param.type_pos) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t.array {\n\t\t\tif !c.ensure_type_exists((sym.info as ast.Array).elem_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.array_fixed {\n\t\t\tif !c.ensure_type_exists((sym.info as ast.ArrayFixed).elem_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.map {\n\t\t\tinfo := sym.info as ast.Map\n\t\t\tif !c.ensure_type_exists(info.key_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !c.ensure_type_exists(info.value_type, pos) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t.sum_type {\n\t\t\tinfo := sym.info as ast.SumType\n\t\t\tfor concrete_typ in info.concrete_types {\n\t\t\t\tif !c.ensure_type_exists(concrete_typ, pos) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {}\n\t}\n\treturn true\n}\n\n// return true if a violation of a shared variable access rule is detected\nfn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what string) bool {\n\tmut pos := token.Pos{}\n\tmatch expr {\n\t\tast.Ident {\n\t\t\tif typ.has_flag(.shared_f) {\n\t\t\t\tif expr.name !in c.rlocked_names && expr.name !in c.locked_names {\n\t\t\t\t\taction := if what == 'argument' { 'passed' } else { 'used' }\n\t\t\t\t\tc.error('`${expr.name}` is `shared` and must be `rlock`ed or `lock`ed to be ${action} as non-mut ${what}',\n\t\t\t\t\t\texpr.pos)\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t\tast.SelectorExpr {\n\t\t\tpos = expr.pos\n\t\t\tif typ.has_flag(.shared_f) {\n\t\t\t\texpr_name := '${expr.expr}.${expr.field_name}'\n\t\t\t\tif expr_name !in c.rlocked_names && expr_name !in c.locked_names {\n\t\t\t\t\taction := if what == 'argument' { 'passed' } else { 'used' }\n\t\t\t\t\tc.error('`${expr_name}` is `shared` and must be `rlock`ed or `lock`ed to be ${action} as non-mut ${what}',\n\t\t\t\t\t\texpr.pos)\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t} else {\n\t\t\t\tif c.fail_if_unreadable(expr.expr, expr.expr_type, what) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tast.CallExpr {\n\t\t\tpos = expr.pos\n\t\t\tif expr.is_method {\n\t\t\t\tif c.fail_if_unreadable(expr.left, expr.left_type, what) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t\tast.LockExpr {\n\t\t\t// TODO: check expressions inside the lock by appending to c.(r)locked_names\n\t\t\treturn false\n\t\t}\n\t\tast.IndexExpr {\n\t\t\tpos = expr.left.pos().extend(expr.pos)\n\t\t\tif c.fail_if_unreadable(expr.left, expr.left_type, what) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\tast.InfixExpr {\n\t\t\tpos = expr.left.pos().extend(expr.pos)\n\t\t\tif c.fail_if_unreadable(expr.left, expr.left_type, what) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif c.fail_if_unreadable(expr.right, expr.right_type, what) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tpos = expr.pos()\n\t\t}\n\t}\n\tif typ.has_flag(.shared_f) {\n\t\tc.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut ${what}',\n\t\t\tpos)\n\t\treturn true\n\t}\n\treturn false\n}\n\nfn (mut c Checker) fail_if_stack_struct_action_outside_unsafe(mut ident ast.Ident, failed_action string) {\n\tif mut ident.obj is ast.Var {\n\t\tmut obj := unsafe { &ident.obj }\n\t\tif c.fn_scope != unsafe { nil } {\n\t\t\tobj = c.fn_scope.find_var(ident.obj.name) or { obj }\n\t\t}\n\t\tif obj.is_stack_obj && !c.inside_unsafe {\n\t\t\tsym := c.table.sym(obj.typ.set_nr_muls(0))\n\t\t\tif !sym.is_heap() && !c.pref.translated && !c.file.is_translated {\n\t\t\t\tsuggestion := if sym.kind == .struct_ {\n\t\t\t\t\t'declaring `${sym.name}` as `[heap]`'\n\t\t\t\t} else {\n\t\t\t\t\t'wrapping the `${sym.name}` object in a `struct` declared as `[heap]`'\n\t\t\t\t}\n\t\t\t\tc.error('`${ident.name}` cannot be ${failed_action} outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.',\n\t\t\t\t\tident.pos)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfn (mut c Checker) goto_label(node ast.GotoLabel) {\n\t// Register a goto label\n\tif node.name !in c.goto_labels {\n\t\tc.goto_labels[node.name] = node\n\t\tc.goto_labels[node.name].is_used = false\n\t}\n}\n\nfn (mut c Checker) goto_stmt(node ast.GotoStmt) {\n\tif c.inside_defer {\n\t\tc.error('goto is not allowed in defer statements', node.pos)\n\t}\n\tif !c.inside_unsafe {\n\t\tif !c.pref.translated && !c.file.is_translated {\n\t\t\tc.warn('`goto` requires `unsafe` (consider using labelled break/continue)',\n\t\t\t\tnode.pos)\n\t\t}\n\t}\n\tif c.table.cur_fn != unsafe { nil } && node.name !in c.table.cur_fn.label_names {\n\t\tc.error('unknown label `${node.name}`', node.pos)\n\t}\n\tc.goto_labels[node.name].is_used = true // Register a label use\n\t// TODO: check label doesn't bypass variable declarations\n}\n\nfn (mut c Checker) check_unused_labels() {\n\tfor name, label in c.goto_labels {\n\t\tif !label.is_used {\n\t\t\t// TODO show label's location\n\t\t\tc.warn('label `${name}` defined and not used', label.pos)\n\t\t\tc.goto_labels[name].is_used = true // so that this warning is not shown again\n\t\t}\n\t}\n}\n\nfn (mut c Checker) deprecate_old_isreftype_and_sizeof_of_a_guessed_type(is_guessed_type bool, typ ast.Type, pos token.Pos, label string) {\n\tif is_guessed_type {\n\t\tstyp := c.table.type_to_str(typ)\n\t\tc.note('`${label}(${styp})` is deprecated. Use `v fmt -w .` to convert it to `${label}[${styp}]()` instead.',\n\t\t\tpos)\n\t}\n}\n\nfn (c &Checker) check_import_sym_conflict(ident string) bool {\n\tfor import_sym in c.file.imports {\n\t\t// Check if alias exists or not\n\t\tif !import_sym.alias.is_blank() {\n\t\t\tif import_sym.alias == ident {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} else if import_sym.mod == ident {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/tests/testdata/benchmarks/inlay_hints.vv",
    "content": "// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.\n// Use of this source code is governed by an MIT license\n// that can be found in the LICENSE file.\nmodule builtin\n\nimport strconv\n\n/*\nNote: A V string should be/is immutable from the point of view of\n    V user programs after it is first created. A V string is\n    also slightly larger than the equivalent C string because\n    the V string also has an integer length attached.\n\n    This tradeoff is made, since V strings are created just *once*,\n    but potentially used *many times* over their lifetime.\n\n    The V string implementation uses a struct, that has a .str field,\n    which points to a C style 0 terminated memory block. Although not\n    strictly necessary from the V point of view, that additional 0\n    is *very useful for C interoperability*.\n\n    The V string implementation also has an integer .len field,\n    containing the length of the .str field, excluding the\n    terminating 0 (just like the C's strlen(s) would do).\n\n    The 0 ending of .str, and the .len field, mean that in practice:\n      a) a V string s can be used very easily, wherever a\n         C string is needed, just by passing s.str,\n         without a need for further conversion/copying.\n\n      b) where strlen(s) is needed, you can just pass s.len,\n         without having to constantly recompute the length of s\n         *over and over again* like some C programs do. This is because\n         V strings are immutable and so their length does not change.\n\n    Ordinary V code *does not need* to be concerned with the\n    additional 0 in the .str field. The 0 *must* be put there by the\n    low level string creating functions inside this module.\n\n    Failing to do this will lead to programs that work most of the\n    time, when used with pure V functions, but fail in strange ways,\n    when used with modules using C functions (for example os and so on).\n*/\npub struct string {\npub:\n\tstr &u8 = 0 // points to a C style 0 terminated string of bytes.\n\tlen int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).\n\t// NB string.is_lit is an enumeration of the following:\n\t// .is_lit == 0 => a fresh string, should be freed by autofree\n\t// .is_lit == 1 => a literal string from .rodata, should NOT be freed\n\t// .is_lit == -98761234 => already freed string, protects against double frees.\n\t// ---------> ^^^^^^^^^ calling free on these is a bug.\n\t// Any other value means that the string has been corrupted.\nmut:\n\tis_lit int\n}\n\n// runes returns an array of all the utf runes in the string `s`\n// which is useful if you want random access to them\n@[direct_array_access]\npub fn (s string) runes() []rune {\n\tmut runes := []rune{cap: s.len}\n\tfor i := 0; i < s.len; i++ {\n\t\tchar_len := utf8_char_len(unsafe { s.str[i] })\n\t\tif char_len > 1 {\n\t\t\tend := if s.len - 1 >= i + char_len { i + char_len } else { s.len }\n\t\t\tmut r := unsafe { s[i..end] }\n\t\t\trunes << r.utf32_code()\n\t\t\ti += char_len - 1\n\t\t} else {\n\t\t\trunes << unsafe { s.str[i] }\n\t\t}\n\t}\n\treturn runes\n}\n\n// cstring_to_vstring creates a new V string copy of the C style string,\n// pointed by `s`. This function is most likely what you want to use when\n// working with C style pointers to 0 terminated strings (i.e. `char*`).\n// It is recommended to use it, unless you *do* understand the implications of\n// tos/tos2/tos3/tos4/tos5 in terms of memory management and interactions with\n// -autofree and `[manualfree]`.\n// It will panic, if the pointer `s` is 0.\n@[unsafe]\npub fn cstring_to_vstring(s &char) string {\n\treturn unsafe { tos2(&u8(s)) }.clone()\n}\n\n// tos_clone creates a new V string copy of the C style string, pointed by `s`.\n// See also cstring_to_vstring (it is the same as it, the only difference is,\n// that tos_clone expects `&byte`, while cstring_to_vstring expects &char).\n// It will panic, if the pointer `s` is 0.\n@[unsafe]\npub fn tos_clone(s &u8) string {\n\treturn unsafe { tos2(s) }.clone()\n}\n\n// tos creates a V string, given a C style pointer to a 0 terminated block.\n// Note: the memory block pointed by s is *reused, not copied*!\n// It will panic, when the pointer `s` is 0.\n// See also `tos_clone`.\n@[unsafe]\npub fn tos(s &u8, len int) string {\n\tif s == 0 {\n\t\tpanic('tos(): nil string')\n\t}\n\treturn string{\n\t\tstr: unsafe { s }\n\t\tlen: len\n\t}\n}\n\n// tos2 creates a V string, given a C style pointer to a 0 terminated block.\n// Note: the memory block pointed by s is *reused, not copied*!\n// It will calculate the length first, thus it is more costly than `tos`.\n// It will panic, when the pointer `s` is 0.\n// It is the same as `tos3`, but for &byte pointers, avoiding callsite casts.\n// See also `tos_clone`.\n@[unsafe]\npub fn tos2(s &u8) string {\n\tif s == 0 {\n\t\tpanic('tos2: nil string')\n\t}\n\treturn string{\n\t\tstr: unsafe { s }\n\t\tlen: unsafe { vstrlen(s) }\n\t}\n}\n\n// tos3 creates a V string, given a C style pointer to a 0 terminated block.\n// Note: the memory block pointed by s is *reused, not copied*!\n// It will calculate the length first, so it is more costly than tos.\n// It will panic, when the pointer `s` is 0.\n// It is the same as `tos2`, but for &char pointers, avoiding callsite casts.\n// See also `tos_clone`.\n@[unsafe]\npub fn tos3(s &char) string {\n\tif s == 0 {\n\t\tpanic('tos3: nil string')\n\t}\n\treturn string{\n\t\tstr: unsafe { &u8(s) }\n\t\tlen: unsafe { vstrlen_char(s) }\n\t}\n}\n\n// tos4 creates a V string, given a C style pointer to a 0 terminated block.\n// Note: the memory block pointed by s is *reused, not copied*!\n// It will calculate the length first, so it is more costly than tos.\n// It returns '', when given a 0 pointer `s`, it does NOT panic.\n// It is the same as `tos5`, but for &byte pointers, avoiding callsite casts.\n// See also `tos_clone`.\n@[unsafe]\npub fn tos4(s &u8) string {\n\tif s == 0 {\n\t\treturn ''\n\t}\n\treturn string{\n\t\tstr: unsafe { s }\n\t\tlen: unsafe { vstrlen(s) }\n\t}\n}\n\n// tos5 creates a V string, given a C style pointer to a 0 terminated block.\n// Note: the memory block pointed by s is *reused, not copied*!\n// It will calculate the length first, so it is more costly than tos.\n// It returns '', when given a 0 pointer `s`, it does NOT panic.\n// It is the same as `tos4`, but for &char pointers, avoiding callsite casts.\n// See also `tos_clone`.\n@[unsafe]\npub fn tos5(s &char) string {\n\tif s == 0 {\n\t\treturn ''\n\t}\n\treturn string{\n\t\tstr: unsafe { &u8(s) }\n\t\tlen: unsafe { vstrlen_char(s) }\n\t}\n}\n\n// vstring converts a C style string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// Note: instead of `&u8(arr.data).vstring()`, do use `tos_clone(&u8(arr.data))`.\n// Strings returned from this function will be normal V strings beside that,\n// (i.e. they would be freed by V's -autofree mechanism, when they are no longer used).\n// See also `tos_clone`.\n@[unsafe]\npub fn (bp &u8) vstring() string {\n\treturn string{\n\t\tstr: unsafe { bp }\n\t\tlen: unsafe { vstrlen(bp) }\n\t}\n}\n\n// vstring_with_len converts a C style 0 terminated string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// This method has lower overhead compared to .vstring(), since it\n// does not need to calculate the length of the 0 terminated string.\n// See also `tos_clone`.\n@[unsafe]\npub fn (bp &u8) vstring_with_len(len int) string {\n\treturn string{\n\t\tstr: unsafe { bp }\n\t\tlen: len\n\t\tis_lit: 0\n\t}\n}\n\n// vstring converts a C style string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// Strings returned from this function will be normal V strings beside that,\n// (i.e. they would be freed by V's -autofree mechanism, when they are\n// no longer used).\n// Note: instead of `&u8(a.data).vstring()`, use `tos_clone(&u8(a.data))`.\n// See also `tos_clone`.\n@[unsafe]\npub fn (cp &char) vstring() string {\n\treturn string{\n\t\tstr: &u8(cp)\n\t\tlen: unsafe { vstrlen_char(cp) }\n\t\tis_lit: 0\n\t}\n}\n\n// vstring_with_len converts a C style 0 terminated string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// This method has lower overhead compared to .vstring(), since it\n// does not calculate the length of the 0 terminated string.\n// See also `tos_clone`.\n@[unsafe]\npub fn (cp &char) vstring_with_len(len int) string {\n\treturn string{\n\t\tstr: &u8(cp)\n\t\tlen: len\n\t\tis_lit: 0\n\t}\n}\n\n// vstring_literal converts a C style string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// NB2: unlike vstring, vstring_literal will mark the string\n// as a literal, so it will not be freed by -autofree.\n// This is suitable for readonly strings, C string literals etc,\n// that can be read by the V program, but that should not be\n// managed/freed by it, for example `os.args` is implemented using it.\n// See also `tos_clone`.\n@[unsafe]\npub fn (bp &u8) vstring_literal() string {\n\treturn string{\n\t\tstr: unsafe { bp }\n\t\tlen: unsafe { vstrlen(bp) }\n\t\tis_lit: 1\n\t}\n}\n\n// vstring_with_len converts a C style string to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// This method has lower overhead compared to .vstring_literal(), since it\n// does not need to calculate the length of the 0 terminated string.\n// See also `tos_clone`.\n@[unsafe]\npub fn (bp &u8) vstring_literal_with_len(len int) string {\n\treturn string{\n\t\tstr: unsafe { bp }\n\t\tlen: len\n\t\tis_lit: 1\n\t}\n}\n\n// vstring_literal converts a C style string char* pointer to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// See also `byteptr.vstring_literal` for more details.\n// See also `tos_clone`.\n@[unsafe]\npub fn (cp &char) vstring_literal() string {\n\treturn string{\n\t\tstr: &u8(cp)\n\t\tlen: unsafe { vstrlen_char(cp) }\n\t\tis_lit: 1\n\t}\n}\n\n// vstring_literal_with_len converts a C style string char* pointer,\n// to a V string.\n// Note: the memory block pointed by `bp` is *reused, not copied*!\n// This method has lower overhead compared to .vstring_literal(), since it\n// does not need to calculate the length of the 0 terminated string.\n// See also `tos_clone`.\n@[unsafe]\npub fn (cp &char) vstring_literal_with_len(len int) string {\n\treturn string{\n\t\tstr: &u8(cp)\n\t\tlen: len\n\t\tis_lit: 1\n\t}\n}\n\n// len_utf8 returns the number of runes contained in the string `s`.\npub fn (s string) len_utf8() int {\n\tmut l := 0\n\tmut i := 0\n\tfor i < s.len {\n\t\tl++\n\t\ti += ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1\n\t}\n\treturn l\n}\n\n// clone_static returns an independent copy of a given array.\n// It should be used only in -autofree generated code.\n@[inline]\nfn (a string) clone_static() string {\n\treturn a.clone()\n}\n\n// option_clone_static returns an independent copy of a given array when lhs is an option type.\n// It should be used only in -autofree generated code.\n@[inline; markused]\nfn (a string) option_clone_static() ?string {\n\treturn ?string(a.clone())\n}\n\n// clone returns a copy of the V string `a`.\npub fn (a string) clone() string {\n\tif a.len <= 0 {\n\t\treturn ''\n\t}\n\tmut b := string{\n\t\tstr: unsafe { malloc_noscan(a.len + 1) }\n\t\tlen: a.len\n\t}\n\tunsafe {\n\t\tvmemcpy(b.str, a.str, a.len)\n\t\tb.str[a.len] = 0\n\t}\n\treturn b\n}\n\n// replace_once replaces the first occurrence of `rep` with the string passed in `with`.\npub fn (s string) replace_once(rep string, with string) string {\n\tidx := s.index_(rep)\n\tif idx == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s.substr(0, idx) + with + s.substr(idx + rep.len, s.len)\n}\n\n// replace replaces all occurrences of `rep` with the string passed in `with`.\n@[direct_array_access]\npub fn (s string) replace(rep string, with string) string {\n\tif s.len == 0 || rep.len == 0 || rep.len > s.len {\n\t\treturn s.clone()\n\t}\n\tif !s.contains(rep) {\n\t\treturn s.clone()\n\t}\n\t// TODO PERF Allocating ints is expensive. Should be a stack array\n\t// Get locations of all reps within this string\n\tmut idxs := []int{cap: s.len / rep.len}\n\tdefer {\n\t\tunsafe { idxs.free() }\n\t}\n\tmut idx := 0\n\tfor {\n\t\tidx = s.index_after(rep, idx) or { break }\n\t\tidxs << idx\n\t\tidx += rep.len\n\t}\n\t// Dont change the string if there's nothing to replace\n\tif idxs.len == 0 {\n\t\treturn s.clone()\n\t}\n\t// Now we know the number of replacements we need to do and we can calc the len of the new string\n\tnew_len := s.len + idxs.len * (with.len - rep.len)\n\tmut b := unsafe { malloc_noscan(new_len + 1) } // add space for the null byte at the end\n\t// Fill the new string\n\tmut b_i := 0\n\tmut s_idx := 0\n\tfor _, rep_pos in idxs {\n\t\tfor i in s_idx .. rep_pos { // copy everything up to piece being replaced\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = s[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t\ts_idx = rep_pos + rep.len // move string index past replacement\n\t\tfor i in 0 .. with.len { // copy replacement piece\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = with[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t}\n\tif s_idx < s.len { // if any original after last replacement, copy it\n\t\tfor i in s_idx .. s.len {\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = s[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t}\n\tunsafe {\n\t\tb[new_len] = 0\n\t\treturn tos(b, new_len)\n\t}\n}\n\nstruct RepIndex {\n\tidx     int\n\tval_idx int\n}\n\n// replace_each replaces all occurrences of the string pairs given in `vals`.\n// Example: assert 'ABCD'.replace_each(['B','C/','C','D','D','C']) == 'AC/DC'\n@[direct_array_access]\npub fn (s string) replace_each(vals []string) string {\n\tif s.len == 0 || vals.len == 0 {\n\t\treturn s.clone()\n\t}\n\tif vals.len % 2 != 0 {\n\t\teprintln('string.replace_each(): odd number of strings')\n\t\treturn s.clone()\n\t}\n\t// `rep` - string to replace\n\t// `with` - string to replace with\n\t// Remember positions of all rep strings, and calculate the length\n\t// of the new string to do just one allocation.\n\tmut new_len := s.len\n\tmut idxs := []RepIndex{cap: 6}\n\tmut idx := 0\n\ts_ := s.clone()\n\tfor rep_i := 0; rep_i < vals.len; rep_i += 2 {\n\t\t// vals: ['rep1, 'with1', 'rep2', 'with2']\n\t\trep := vals[rep_i]\n\t\twith := vals[rep_i + 1]\n\n\t\tfor {\n\t\t\tidx = s_.index_after(rep, idx) or { break } \n\t\t\t// The string already found is set to `/del`, to avoid duplicate searches.\n\t\t\tfor i in 0 .. rep.len {\n\t\t\t\tunsafe {\n\t\t\t\t\ts_.str[idx + i] = 127\n\t\t\t\t}\n\t\t\t}\n\t\t\t// We need to remember both the position in the string,\n\t\t\t// and which rep/with pair it refers to.\n\n\t\t\tidxs << RepIndex{\n\t\t\t\tidx: idx\n\t\t\t\tval_idx: rep_i\n\t\t\t}\n\n\t\t\tidx += rep.len\n\t\t\tnew_len += with.len - rep.len\n\t\t}\n\t}\n\n\t// Dont change the string if there's nothing to replace\n\tif idxs.len == 0 {\n\t\treturn s.clone()\n\t}\n\tidxs.sort(a.idx < b.idx)\n\tmut b := unsafe { malloc_noscan(new_len + 1) } // add space for 0 terminator\n\t// Fill the new string\n\tmut idx_pos := 0\n\tmut cur_idx := idxs[idx_pos]\n\tmut b_i := 0\n\tfor i := 0; i < s.len; i++ {\n\t\tif i == cur_idx.idx {\n\t\t\t// Reached the location of rep, replace it with \"with\"\n\t\t\trep := vals[cur_idx.val_idx]\n\t\t\twith := vals[cur_idx.val_idx + 1]\n\t\t\tfor j in 0 .. with.len {\n\t\t\t\tunsafe {\n\t\t\t\t\tb[b_i] = with[j]\n\t\t\t\t}\n\t\t\t\tb_i++\n\t\t\t}\n\t\t\t// Skip the length of rep, since we just replaced it with \"with\"\n\t\t\ti += rep.len - 1\n\t\t\t// Go to the next index\n\t\t\tidx_pos++\n\t\t\tif idx_pos < idxs.len {\n\t\t\t\tcur_idx = idxs[idx_pos]\n\t\t\t}\n\t\t} else {\n\t\t\t// Rep doesnt start here, just copy\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = s.str[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t}\n\tunsafe {\n\t\tb[new_len] = 0\n\t\treturn tos(b, new_len)\n\t}\n}\n\n// replace_char replaces all occurrences of the character `rep` multiple occurrences of the character passed in `with` with respect to `repeat`.\n// Example: assert '\\tHello!'.replace_char(`\\t`,` `,8) == '        Hello!'\n@[direct_array_access]\npub fn (s string) replace_char(rep u8, with u8, repeat int) string {\n\t$if !no_bounds_checking {\n\t\tif repeat <= 0 {\n\t\t\tpanic('string.replace_char(): tab length too short')\n\t\t}\n\t}\n\tif s.len == 0 {\n\t\treturn s.clone()\n\t}\n\t// TODO Allocating ints is expensive. Should be a stack array\n\t// - string.replace()\n\tmut idxs := []int{cap: s.len}\n\tdefer {\n\t\tunsafe { idxs.free() }\n\t}\n\t// No need to do a contains(), it already traverses the entire string\n\tfor i, ch in s {\n\t\tif ch == rep { // Found char? Mark its location\n\t\t\tidxs << i\n\t\t}\n\t}\n\tif idxs.len == 0 {\n\t\treturn s.clone()\n\t}\n\t// Now we know the number of replacements we need to do and we can calc the len of the new string\n\tnew_len := s.len + idxs.len * (repeat - 1)\n\tmut b := unsafe { malloc_noscan(new_len + 1) } // add space for the null byte at the end\n\t// Fill the new string\n\tmut b_i := 0\n\tmut s_idx := 0\n\tfor rep_pos in idxs {\n\t\tfor i in s_idx .. rep_pos { // copy everything up to piece being replaced\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = s[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t\ts_idx = rep_pos + 1 // move string index past replacement\n\t\tfor _ in 0 .. repeat { // copy replacement piece\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = with\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t}\n\tif s_idx < s.len { // if any original after last replacement, copy it\n\t\tfor i in s_idx .. s.len {\n\t\t\tunsafe {\n\t\t\t\tb[b_i] = s[i]\n\t\t\t}\n\t\t\tb_i++\n\t\t}\n\t}\n\tunsafe {\n\t\tb[new_len] = 0\n\t\treturn tos(b, new_len)\n\t}\n}\n\n// normalize_tabs replaces all tab characters with `tab_len` amount of spaces\n// Example: assert '\\t\\tpop rax\\t; pop rax'.normalize_tabs(2) == '    pop rax  ; pop rax'\n@[inline]\npub fn (s string) normalize_tabs(tab_len int) string {\n\treturn s.replace_char(`\\t`, ` `, tab_len)\n}\n\n// bool returns `true` if the string equals the word \"true\" it will return `false` otherwise.\n@[inline]\npub fn (s string) bool() bool {\n\treturn s == 'true' || s == 't' // TODO t for pg, remove\n}\n\n// int returns the value of the string as an integer `'1'.int() == 1`.\n@[inline]\npub fn (s string) int() int {\n\treturn int(strconv.common_parse_int(s, 0, 32, false, false) or { 0 })\n}\n\n// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`.\n@[inline]\npub fn (s string) i64() i64 {\n\treturn strconv.common_parse_int(s, 0, 64, false, false) or { 0 }\n}\n\n// i8 returns the value of the string as i8 `'1'.i8() == i8(1)`.\n@[inline]\npub fn (s string) i8() i8 {\n\treturn i8(strconv.common_parse_int(s, 0, 8, false, false) or { 0 })\n}\n\n// i16 returns the value of the string as i16 `'1'.i16() == i16(1)`.\n@[inline]\npub fn (s string) i16() i16 {\n\treturn i16(strconv.common_parse_int(s, 0, 16, false, false) or { 0 })\n}\n\n// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`.\n@[inline]\npub fn (s string) f32() f32 {\n\treturn f32(strconv.atof64(s) or { 0 })\n}\n\n// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`.\n@[inline]\npub fn (s string) f64() f64 {\n\treturn strconv.atof64(s) or { 0 }\n}\n\n// u8 returns the value of the string as u8 `'1'.u8() == u8(1)`.\n@[inline]\npub fn (s string) u8() u8 {\n\treturn u8(strconv.common_parse_uint(s, 0, 8, false, false) or { 0 })\n}\n\n// u8_array returns the value of the hex/bin string as u8 array.\n// hex string example: `'0x11223344ee'.u8_array() == [u8(0x11),0x22,0x33,0x44,0xee]`.\n// bin string example: `'0b1101_1101'.u8_array() == [u8(0xdd)]`.\n// underscore in the string will be stripped.\npub fn (s string) u8_array() []u8 {\n\t// strip underscore in the string\n\tmut tmps := s.replace('_', '')\n\tif tmps.len == 0 {\n\t\treturn []u8{}\n\t}\n\ttmps = tmps.to_lower()\n\tif tmps.starts_with('0x') {\n\t\ttmps = tmps[2..]\n\t\tif tmps.len == 0 {\n\t\t\treturn []u8{}\n\t\t}\n\t\t// make sure every digit is valid hex digit\n\t\tif !tmps.contains_only('0123456789abcdef') {\n\t\t\treturn []u8{}\n\t\t}\n\t\t// make sure tmps has even hex digits\n\t\tif tmps.len % 2 == 1 {\n\t\t\ttmps = '0' + tmps\n\t\t}\n\n\t\tmut ret := []u8{len: tmps.len / 2}\n\t\tfor i in 0 .. ret.len {\n\t\t\tret[i] = u8(tmps[2 * i..2 * i + 2].parse_uint(16, 8) or { 0 })\n\t\t}\n\t\treturn ret\n\t} else if tmps.starts_with('0b') {\n\t\ttmps = tmps[2..]\n\t\tif tmps.len == 0 {\n\t\t\treturn []u8{}\n\t\t}\n\t\t// make sure every digit is valid binary digit\n\t\tif !tmps.contains_only('01') {\n\t\t\treturn []u8{}\n\t\t}\n\t\t// make sure tmps has multiple of 8 binary digits\n\t\tif tmps.len % 8 != 0 {\n\t\t\ttmps = '0'.repeat(8 - tmps.len % 8) + tmps\n\t\t}\n\n\t\tmut ret := []u8{len: tmps.len / 8}\n\t\tfor i in 0 .. ret.len {\n\t\t\tret[i] = u8(tmps[8 * i..8 * i + 8].parse_uint(2, 8) or { 0 })\n\t\t}\n\t\treturn ret\n\t}\n\treturn []u8{}\n}\n\n// u16 returns the value of the string as u16 `'1'.u16() == u16(1)`.\n@[inline]\npub fn (s string) u16() u16 {\n\treturn u16(strconv.common_parse_uint(s, 0, 16, false, false) or { 0 })\n}\n\n// u32 returns the value of the string as u32 `'1'.u32() == u32(1)`.\n@[inline]\npub fn (s string) u32() u32 {\n\treturn u32(strconv.common_parse_uint(s, 0, 32, false, false) or { 0 })\n}\n\n// u64 returns the value of the string as u64 `'1'.u64() == u64(1)`.\n@[inline]\npub fn (s string) u64() u64 {\n\treturn strconv.common_parse_uint(s, 0, 64, false, false) or { 0 }\n}\n\n// parse_uint is like `parse_int` but for unsigned numbers\n//\n// This method directly exposes the `parse_uint` function from `strconv`\n// as a method on `string`. For more advanced features,\n// consider calling `strconv.common_parse_uint` directly.\n@[inline]\npub fn (s string) parse_uint(_base int, _bit_size int) !u64 {\n\treturn strconv.parse_uint(s, _base, _bit_size)\n}\n\n// parse_int interprets a string s in the given base (0, 2 to 36) and\n// bit size (0 to 64) and returns the corresponding value i.\n//\n// If the base argument is 0, the true base is implied by the string's\n// prefix: 2 for \"0b\", 8 for \"0\" or \"0o\", 16 for \"0x\", and 10 otherwise.\n// Also, for argument base 0 only, underscore characters are permitted\n// as defined by the Go syntax for integer literals.\n//\n// The bitSize argument specifies the integer type\n// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64\n// correspond to int, int8, int16, int32, and int64.\n// If bitSize is below 0 or above 64, an error is returned.\n//\n// This method directly exposes the `parse_int` function from `strconv`\n// as a method on `string`. For more advanced features,\n// consider calling `strconv.common_parse_int` directly.\n@[inline]\npub fn (s string) parse_int(_base int, _bit_size int) !i64 {\n\treturn strconv.parse_int(s, _base, _bit_size)\n}\n\n@[direct_array_access]\nfn (s string) == (a string) bool {\n\tif s.str == 0 {\n\t\t// should never happen\n\t\tpanic('string.eq(): nil string')\n\t}\n\tif s.len != a.len {\n\t\treturn false\n\t}\n\tif s.len > 0 {\n\t\tlast_idx := s.len - 1\n\t\tif s[last_idx] != a[last_idx] {\n\t\t\treturn false\n\t\t}\n\t}\n\tunsafe {\n\t\treturn vmemcmp(s.str, a.str, a.len) == 0\n\t}\n}\n\n// compare returns -1 if `s` < `a`, 0 if `s` == `a`, and 1 if `s` > `a`\n@[direct_array_access]\npub fn (s string) compare(a string) int {\n\tmin_len := if s.len < a.len { s.len } else { a.len }\n\tfor i in 0 .. min_len {\n\t\tif s[i] < a[i] {\n\t\t\treturn -1\n\t\t}\n\t\tif s[i] > a[i] {\n\t\t\treturn 1\n\t\t}\n\t}\n\tif s.len < a.len {\n\t\treturn -1\n\t}\n\tif s.len > a.len {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\n@[direct_array_access]\nfn (s string) < (a string) bool {\n\tfor i in 0 .. s.len {\n\t\tif i >= a.len || s[i] > a[i] {\n\t\t\treturn false\n\t\t} else if s[i] < a[i] {\n\t\t\treturn true\n\t\t}\n\t}\n\tif s.len < a.len {\n\t\treturn true\n\t}\n\treturn false\n}\n\n@[direct_array_access]\nfn (s string) + (a string) string {\n\tnew_len := a.len + s.len\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(new_len + 1) }\n\t\tlen: new_len\n\t}\n\tunsafe {\n\t\tvmemcpy(res.str, s.str, s.len)\n\t\tvmemcpy(res.str + s.len, a.str, a.len)\n\t}\n\tunsafe {\n\t\tres.str[new_len] = 0 // V strings are not null terminated, but just in case\n\t}\n\treturn res\n}\n\n// split_any splits the string to an array by any of the `delim` chars.\n// Example: \"first row\\nsecond row\".split_any(\" \\n\") == ['first', 'row', 'second', 'row']\n// Split a string using the chars in the delimiter string as delimiters chars.\n// If the delimiter string is empty then `.split()` is used.\n@[direct_array_access]\npub fn (s string) split_any(delim string) []string {\n\tmut res := []string{}\n\tmut i := 0\n\t// check empty source string\n\tif s.len > 0 {\n\t\t// if empty delimiter string using default split\n\t\tif delim.len <= 0 {\n\t\t\treturn s.split('')\n\t\t}\n\t\tfor index, ch in s {\n\t\t\tfor delim_ch in delim {\n\t\t\t\tif ch == delim_ch {\n\t\t\t\t\tres << s[i..index]\n\t\t\t\t\ti = index + 1\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif i < s.len {\n\t\t\tres << s[i..]\n\t\t}\n\t}\n\treturn res\n}\n\n// rsplit_any splits the string to an array by any of the `delim` chars in reverse order.\n// Example: \"first row\\nsecond row\".rsplit_any(\" \\n\") == ['row', 'second', 'row', 'first']\n// Split a string using the chars in the delimiter string as delimiters chars.\n// If the delimiter string is empty then `.rsplit()` is used.\n@[direct_array_access]\npub fn (s string) rsplit_any(delim string) []string {\n\tmut res := []string{}\n\tmut i := s.len - 1\n\tif s.len > 0 {\n\t\tif delim.len <= 0 {\n\t\t\treturn s.rsplit('')\n\t\t}\n\t\tmut rbound := s.len\n\t\tfor i >= 0 {\n\t\t\tfor delim_ch in delim {\n\t\t\t\tif s[i] == delim_ch {\n\t\t\t\t\tres << s[i + 1..rbound]\n\t\t\t\t\trbound = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\ti--\n\t\t}\n\t\tif rbound > 0 {\n\t\t\tres << s[..rbound]\n\t\t}\n\t}\n\treturn res\n}\n\n// split splits the string into an array of strings at the given delimiter.\n// Example: assert 'A B C'.split(' ') == ['A','B','C']\n// If `delim` is empty the string is split by it's characters.\n// Example: assert 'DEF'.split('') == ['D','E','F']\n@[inline]\npub fn (s string) split(delim string) []string {\n\treturn s.split_nth(delim, 0)\n}\n\n// rsplit splits the string into an array of strings at the given delimiter, starting from the right.\n// Example: assert 'A B C'.rsplit(' ') == ['C','B','A']\n// If `delim` is empty the string is split by it's characters.\n// Example: assert 'DEF'.rsplit('') == ['F','E','D']\n@[inline]\npub fn (s string) rsplit(delim string) []string {\n\treturn s.rsplit_nth(delim, 0)\n}\n\n// split_once splits the string into a pair of strings at the given delimiter.\n// Example:\n// ```v\n// path, ext := 'file.ts.dts'.split_once('.')?\n// assert path == 'file'\n// assert ext == 'ts.dts'\npub fn (s string) split_once(delim string) ?(string, string) {\n\tresult := s.split_nth(delim, 2)\n\n\tif result.len != 2 {\n\t\treturn none\n\t}\n\n\treturn result[0], result[1]\n}\n\n// rsplit_once splits the string into a pair of strings at the given delimiter, starting from the right.\n// Example:\n// ```v\n// path, ext := 'file.ts.dts'.rsplit_once('.')?\n// assert path == 'file.ts'\n// assert ext == 'dts'\n// ```\n// NOTE: rsplit_once returns the string at the left side of the delimiter as first part of the pair.\npub fn (s string) rsplit_once(delim string) ?(string, string) {\n\tresult := s.rsplit_nth(delim, 2)\n\n\tif result.len != 2 {\n\t\treturn none\n\t}\n\n\treturn result[1], result[0]\n}\n\n// split_nth splits the string based on the passed `delim` substring.\n// It returns the first Nth parts. When N=0, return all the splits.\n// The last returned element has the remainder of the string, even if\n// the remainder contains more `delim` substrings.\n@[direct_array_access]\npub fn (s string) split_nth(delim string, nth int) []string {\n\tmut res := []string{}\n\tmut i := 0\n\n\tmatch delim.len {\n\t\t0 {\n\t\t\ti = 1\n\t\t\tfor ch in s {\n\t\t\t\tif nth > 0 && i >= nth {\n\t\t\t\t\tres << s[i - 1..]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tres << ch.ascii_str()\n\t\t\t\ti++\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t\t1 {\n\t\t\tmut start := 0\n\t\t\tdelim_byte := delim[0]\n\n\t\t\tfor i < s.len {\n\t\t\t\tif s[i] == delim_byte {\n\t\t\t\t\twas_last := nth > 0 && res.len == nth - 1\n\t\t\t\t\tif was_last {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tval := s.substr(start, i)\n\t\t\t\t\tres << val\n\t\t\t\t\tstart = i + delim.len\n\t\t\t\t\ti = start\n\t\t\t\t} else {\n\t\t\t\t\ti++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Then the remaining right part of the string\n\t\t\tif nth < 1 || res.len < nth {\n\t\t\t\tres << s[start..]\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t\telse {\n\t\t\tmut start := 0\n\t\t\t// Take the left part for each delimiter occurrence\n\t\t\tfor i <= s.len {\n\t\t\t\tis_delim := i + delim.len <= s.len && s.substr(i, i + delim.len) == delim\n\t\t\t\tif is_delim {\n\t\t\t\t\twas_last := nth > 0 && res.len == nth - 1\n\t\t\t\t\tif was_last {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tval := s.substr(start, i)\n\t\t\t\t\tres << val\n\t\t\t\t\tstart = i + delim.len\n\t\t\t\t\ti = start\n\t\t\t\t} else {\n\t\t\t\t\ti++\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Then the remaining right part of the string\n\t\t\tif nth < 1 || res.len < nth {\n\t\t\t\tres << s[start..]\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t}\n}\n\n// rsplit_nth splits the string based on the passed `delim` substring in revese order.\n// It returns the first Nth parts. When N=0, return all the splits.\n// The last returned element has the remainder of the string, even if\n// the remainder contains more `delim` substrings.\n@[direct_array_access]\npub fn (s string) rsplit_nth(delim string, nth int) []string {\n\tmut res := []string{}\n\tmut i := s.len - 1\n\n\tmatch delim.len {\n\t\t0 {\n\t\t\tfor i >= 0 {\n\t\t\t\tif nth > 0 && res.len == nth - 1 {\n\t\t\t\t\tres << s[..i + 1]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tres << s[i].ascii_str()\n\t\t\t\ti--\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t\t1 {\n\t\t\tmut rbound := s.len\n\t\t\tdelim_byte := delim[0]\n\n\t\t\tfor i >= 0 {\n\t\t\t\tif s[i] == delim_byte {\n\t\t\t\t\tif nth > 0 && res.len == nth - 1 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tres << s[i + 1..rbound]\n\t\t\t\t\trbound = i\n\t\t\t\t\ti--\n\t\t\t\t} else {\n\t\t\t\t\ti--\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif nth < 1 || res.len < nth {\n\t\t\t\tres << s[..rbound]\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t\telse {\n\t\t\tmut rbound := s.len\n\n\t\t\tfor i >= 0 {\n\t\t\t\tis_delim := i - delim.len >= 0 && s[i - delim.len..i] == delim\n\t\t\t\tif is_delim {\n\t\t\t\t\tif nth > 0 && res.len == nth - 1 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tres << s[i..rbound]\n\t\t\t\t\trbound = i - delim.len\n\t\t\t\t\ti -= delim.len\n\t\t\t\t} else {\n\t\t\t\t\ti--\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif nth < 1 || res.len < nth {\n\t\t\t\tres << s[..rbound]\n\t\t\t}\n\t\t\treturn res\n\t\t}\n\t}\n}\n\n// split_into_lines splits the string by newline characters.\n// newlines are stripped.\n// `\\r` (MacOS), `\\n` (POSIX), and `\\r\\n` (WinOS) line endings are all supported (including mixed line endings).\n// NOTE: algorithm is \"greedy\", consuming '\\r\\n' as a single line ending with higher priority than '\\r' and '\\n' as multiple endings\n@[direct_array_access]\npub fn (s string) split_into_lines() []string {\n\tmut res := []string{}\n\tif s.len == 0 {\n\t\treturn res\n\t}\n\tcr := `\\r`\n\tlf := `\\n`\n\tmut line_start := 0\n\tfor i := 0; i < s.len; i++ {\n\t\tif line_start <= i {\n\t\t\tif s[i] == lf {\n\t\t\t\tres << if line_start == i { '' } else { s[line_start..i] }\n\t\t\t\tline_start = i + 1\n\t\t\t} else if s[i] == cr {\n\t\t\t\tres << if line_start == i { '' } else { s[line_start..i] }\n\t\t\t\tif (i + 1) < s.len && s[i + 1] == lf {\n\t\t\t\t\tline_start = i + 2\n\t\t\t\t} else {\n\t\t\t\t\tline_start = i + 1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif line_start < s.len {\n\t\tres << s[line_start..]\n\t}\n\treturn res\n}\n\n// substr returns the string between index positions `start` and `end`.\n// Example: assert 'ABCD'.substr(1,3) == 'BC'\n@[direct_array_access]\npub fn (s string) substr(start int, _end int) string {\n\tend := if _end == max_int { s.len } else { _end } // max_int\n\t$if !no_bounds_checking {\n\t\tif start > end || start > s.len || end > s.len || start < 0 || end < 0 {\n\t\t\tpanic('substr(${start}, ${end}) out of bounds (len=${s.len})')\n\t\t}\n\t}\n\tlen := end - start\n\tif len == s.len {\n\t\treturn s.clone()\n\t}\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(len + 1) }\n\t\tlen: len\n\t}\n\tunsafe {\n\t\tvmemcpy(res.str, s.str + start, len)\n\t\tres.str[len] = 0\n\t}\n\treturn res\n}\n\n// substr_unsafe works like substr(), but doesn't copy (allocate) the substring\n@[direct_array_access]\npub fn (s string) substr_unsafe(start int, _end int) string {\n\tend := if _end == 2147483647 { s.len } else { _end } // max_int\n\tlen := end - start\n\tif len == s.len {\n\t\treturn s\n\t}\n\treturn string{\n\t\tstr: unsafe { s.str + start }\n\t\tlen: len\n\t}\n}\n\n// version of `substr()` that is used in `a[start..end] or {`\n// return an error when the index is out of range\n@[direct_array_access]\npub fn (s string) substr_with_check(start int, _end int) !string {\n\tend := if _end == max_int { s.len } else { _end } // max_int\n\tif start > end || start > s.len || end > s.len || start < 0 || end < 0 {\n\t\treturn error('substr(${start}, ${end}) out of bounds (len=${s.len})')\n\t}\n\tlen := end - start\n\tif len == s.len {\n\t\treturn s.clone()\n\t}\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(len + 1) }\n\t\tlen: len\n\t}\n\tunsafe {\n\t\tvmemcpy(res.str, s.str + start, len)\n\t\tres.str[len] = 0\n\t}\n\treturn res\n}\n\n// substr_ni returns the string between index positions `start` and `end` allowing negative indexes\n// This function always return a valid string.\n@[direct_array_access]\npub fn (s string) substr_ni(_start int, _end int) string {\n\tmut start := _start\n\tmut end := if _end == max_int { s.len } else { _end } // max_int\n\n\t// borders math\n\tif start < 0 {\n\t\tstart = s.len + start\n\t\tif start < 0 {\n\t\t\tstart = 0\n\t\t}\n\t}\n\n\tif end < 0 {\n\t\tend = s.len + end\n\t\tif end < 0 {\n\t\t\tend = 0\n\t\t}\n\t}\n\tif end >= s.len {\n\t\tend = s.len\n\t}\n\n\tif start > s.len || end < start {\n\t\treturn ''\n\t}\n\n\tlen := end - start\n\n\t// string copy\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(len + 1) }\n\t\tlen: len\n\t}\n\tunsafe {\n\t\tvmemcpy(res.str, s.str + start, len)\n\t\tres.str[len] = 0\n\t}\n\treturn res\n}\n\n// index returns the position of the first character of the input string.\n// It will return `-1` if the input string can't be found.\n@[direct_array_access]\nfn (s string) index_(p string) int {\n\tif p.len > s.len || p.len == 0 {\n\t\treturn -1\n\t}\n\tif p.len > 2 {\n\t\treturn s.index_kmp(p)\n\t}\n\tmut i := 0\n\tfor i < s.len {\n\t\tmut j := 0\n\t\tfor j < p.len && unsafe { s.str[i + j] == p.str[j] } {\n\t\t\tj++\n\t\t}\n\t\tif j == p.len {\n\t\t\treturn i\n\t\t}\n\t\ti++\n\t}\n\treturn -1\n}\n\n// index returns the position of the first character of the first occurrence of the `needle` string in `s`.\n// It will return `none` if the `needle` string can't be found in `s`.\npub fn (s string) index(p string) ?int {\n\tidx := s.index_(p)\n\tif idx == -1 {\n\t\treturn none\n\t}\n\treturn idx\n}\n\n// index_last returns the position of the first character of the *last* occurrence of the `needle` string in `s`.\npub fn (s string) index_last(needle string) ?int {\n\tidx := s.index_last_(needle)\n\tif idx == -1 {\n\t\treturn none\n\t}\n\treturn idx\n}\n\n// last_index returns the position of the first character of the *last* occurrence of the `needle` string in `s`.\n@[deprecated: 'use `.index_last(needle string)` instead']\n@[deprecated_after: '2023-12-18']\n@[inline]\npub fn (s string) last_index(needle string) ?int {\n\treturn s.index_last(needle)\n}\n\n// index_kmp does KMP search.\n@[direct_array_access; manualfree]\nfn (s string) index_kmp(p string) int {\n\tif p.len > s.len {\n\t\treturn -1\n\t}\n\tmut prefix := []int{len: p.len}\n\tdefer {\n\t\tunsafe { prefix.free() }\n\t}\n\tmut j := 0\n\tfor i := 1; i < p.len; i++ {\n\t\tfor unsafe { p.str[j] != p.str[i] } && j > 0 {\n\t\t\tj = prefix[j - 1]\n\t\t}\n\t\tif unsafe { p.str[j] == p.str[i] } {\n\t\t\tj++\n\t\t}\n\t\tprefix[i] = j\n\t}\n\tj = 0\n\tfor i in 0 .. s.len {\n\t\tfor unsafe { p.str[j] != s.str[i] } && j > 0 {\n\t\t\tj = prefix[j - 1]\n\t\t}\n\t\tif unsafe { p.str[j] == s.str[i] } {\n\t\t\tj++\n\t\t}\n\t\tif j == p.len {\n\t\t\treturn i - p.len + 1\n\t\t}\n\t}\n\treturn -1\n}\n\n// index_any returns the position of any of the characters in the input string - if found.\npub fn (s string) index_any(chars string) int {\n\tfor i, ss in s {\n\t\tfor c in chars {\n\t\t\tif c == ss {\n\t\t\t\treturn i\n\t\t\t}\n\t\t}\n\t}\n\treturn -1\n}\n\n// index_last_ returns the position of the last occurrence of the given string `p` in `s`.\n@[direct_array_access]\nfn (s string) index_last_(p string) int {\n\tif p.len > s.len || p.len == 0 {\n\t\treturn -1\n\t}\n\tmut i := s.len - p.len\n\tfor i >= 0 {\n\t\tmut j := 0\n\t\tfor j < p.len && unsafe { s.str[i + j] == p.str[j] } {\n\t\t\tj++\n\t\t}\n\t\tif j == p.len {\n\t\t\treturn i\n\t\t}\n\t\ti--\n\t}\n\treturn -1\n}\n\n// index_after returns the position of the input string, starting search from `start` position.\n@[direct_array_access]\npub fn (s string) index_after(p string, start int) int {\n\tif p.len > s.len {\n\t\treturn -1\n\t}\n\tmut strt := start\n\tif start < 0 {\n\t\tstrt = 0\n\t}\n\tif start >= s.len {\n\t\treturn -1\n\t}\n\tmut i := strt\n\tfor i < s.len {\n\t\tmut j := 0\n\t\tmut ii := i\n\t\tfor j < p.len && unsafe { s.str[ii] == p.str[j] } {\n\t\t\tj++\n\t\t\tii++\n\t\t}\n\t\tif j == p.len {\n\t\t\treturn i\n\t\t}\n\t\ti++\n\t}\n\treturn -1\n}\n\n// index_u8 returns the index of byte `c` if found in the string.\n// index_u8 returns -1 if the byte can not be found.\n@[direct_array_access]\npub fn (s string) index_u8(c u8) int {\n\tfor i, b in s {\n\t\tif b == c {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// index_u8_last returns the index of the *last* occurrence of the byte `c` (if found) in the string.\n// It returns -1, if `c` is not found.\n@[direct_array_access]\npub fn (s string) index_u8_last(c u8) int {\n\tfor i := s.len - 1; i >= 0; i-- {\n\t\tif unsafe { s.str[i] == c } {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// last_index_u8 returns the index of the last occurrence of byte `c` if found in the string.\n// It returns -1, if the byte `c` is not found.\n@[deprecated: 'use `.index_u8_last(c u8)` instead']\n@[deprecated_after: '2023-12-18']\n@[inline]\npub fn (s string) last_index_u8(c u8) int {\n\treturn s.index_u8_last(c)\n}\n\n// count returns the number of occurrences of `substr` in the string.\n// count returns -1 if no `substr` could be found.\n@[direct_array_access]\npub fn (s string) count(substr string) int {\n\tif s.len == 0 || substr.len == 0 {\n\t\treturn 0\n\t}\n\tif substr.len > s.len {\n\t\treturn 0\n\t}\n\n\tmut n := 0\n\n\tif substr.len == 1 {\n\t\ttarget := substr[0]\n\n\t\tfor letter in s {\n\t\t\tif letter == target {\n\t\t\t\tn++\n\t\t\t}\n\t\t}\n\n\t\treturn n\n\t}\n\n\tmut i := 0\n\tfor {\n\t\ti = s.index_after(substr, i) or { return n }\n\t\ti += substr.len\n\t\tn++\n\t}\n\treturn 0 // TODO can never get here - v doesn't know that\n}\n\n// contains_u8 returns `true` if the string contains the byte value `x`.\n// See also: [`string.index_u8`](#string.index_u8) , to get the index of the byte as well.\npub fn (s string) contains_u8(x u8) bool {\n\tfor c in s {\n\t\tif x == c {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// contains returns `true` if the string contains `substr`.\n// See also: [`string.index`](#string.index)\npub fn (s string) contains(substr string) bool {\n\tif substr.len == 0 {\n\t\treturn true\n\t}\n\tif substr.len == 1 {\n\t\treturn s.contains_u8(unsafe { substr.str[0] })\n\t}\n\treturn s.index_(substr) != -1\n}\n\n// contains_any returns `true` if the string contains any chars in `chars`.\npub fn (s string) contains_any(chars string) bool {\n\tfor c in chars {\n\t\tif s.contains_u8(c) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// contains_only returns `true`, if the string contains only the characters in `chars`.\npub fn (s string) contains_only(chars string) bool {\n\tif chars.len == 0 {\n\t\treturn false\n\t}\n\tfor ch in s {\n\t\tmut res := 0\n\t\tfor i := 0; i < chars.len && res == 0; i++ {\n\t\t\tres += int(ch == unsafe { chars.str[i] })\n\t\t}\n\t\tif res == 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// contains_any_substr returns `true` if the string contains any of the strings in `substrs`.\npub fn (s string) contains_any_substr(substrs []string) bool {\n\tif substrs.len == 0 {\n\t\treturn true\n\t}\n\tfor sub in substrs {\n\t\tif s.contains(sub) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// starts_with returns `true` if the string starts with `p`.\n@[direct_array_access]\npub fn (s string) starts_with(p string) bool {\n\tif p.len > s.len {\n\t\treturn false\n\t}\n\tfor i in 0 .. p.len {\n\t\tif unsafe { s.str[i] != p.str[i] } {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// ends_with returns `true` if the string ends with `p`.\n@[direct_array_access]\npub fn (s string) ends_with(p string) bool {\n\tif p.len > s.len {\n\t\treturn false\n\t}\n\tfor i in 0 .. p.len {\n\t\tif unsafe { p.str[i] != s.str[s.len - p.len + i] } {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// to_lower returns the string in all lowercase characters.\n// TODO only works with ASCII\n@[direct_array_access]\npub fn (s string) to_lower() string {\n\tunsafe {\n\t\tmut b := malloc_noscan(s.len + 1)\n\t\tfor i in 0 .. s.len {\n\t\t\tif s.str[i] >= `A` && s.str[i] <= `Z` {\n\t\t\t\tb[i] = s.str[i] + 32\n\t\t\t} else {\n\t\t\t\tb[i] = s.str[i]\n\t\t\t}\n\t\t}\n\t\tb[s.len] = 0\n\t\treturn tos(b, s.len)\n\t}\n}\n\n// is_lower returns `true` if all characters in the string are lowercase.\n// Example: assert 'hello developer'.is_lower() == true\n@[direct_array_access]\npub fn (s string) is_lower() bool {\n\tfor i in 0 .. s.len {\n\t\tif s[i] >= `A` && s[i] <= `Z` {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// to_upper returns the string in all uppercase characters.\n// Example: assert 'Hello V'.to_upper() == 'HELLO V'\n@[direct_array_access]\npub fn (s string) to_upper() string {\n\tunsafe {\n\t\tmut b := malloc_noscan(s.len + 1)\n\t\tfor i in 0 .. s.len {\n\t\t\tif s.str[i] >= `a` && s.str[i] <= `z` {\n\t\t\t\tb[i] = s.str[i] - 32\n\t\t\t} else {\n\t\t\t\tb[i] = s.str[i]\n\t\t\t}\n\t\t}\n\t\tb[s.len] = 0\n\t\treturn tos(b, s.len)\n\t}\n}\n\n// is_upper returns `true` if all characters in the string are uppercase.\n// See also: [`byte.is_capital`](#byte.is_capital)\n// Example: assert 'HELLO V'.is_upper() == true\n@[direct_array_access]\npub fn (s string) is_upper() bool {\n\tfor i in 0 .. s.len {\n\t\tif s[i] >= `a` && s[i] <= `z` {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// capitalize returns the string with the first character capitalized.\n// Example: assert 'hello'.capitalize() == 'Hello'\n@[direct_array_access]\npub fn (s string) capitalize() string {\n\tif s.len == 0 {\n\t\treturn ''\n\t}\n\ts0 := s[0]\n\tletter := s0.ascii_str()\n\tuletter := letter.to_upper()\n\tif s.len == 1 {\n\t\treturn uletter\n\t}\n\tsrest := s[1..]\n\tres := uletter + srest\n\treturn res\n}\n\n// uncapitalize returns the string with the first character uncapitalized.\n// Example: assert 'Hello, Bob!'.uncapitalize() == 'hello, Bob!'\n@[direct_array_access]\npub fn (s string) uncapitalize() string {\n\tif s.len == 0 {\n\t\treturn ''\n\t}\n\ts0 := s[0]\n\tletter := s0.ascii_str()\n\tuletter := letter.to_lower()\n\tif s.len == 1 {\n\t\treturn uletter\n\t}\n\tsrest := s[1..]\n\tres := uletter + srest\n\treturn res\n}\n\n// is_capital returns `true`, if the first character in the string `s`,\n// is a capital letter, and the rest are NOT.\n// Example: assert 'Hello'.is_capital() == true\n// Example: assert 'HelloWorld'.is_capital() == false\n@[direct_array_access]\npub fn (s string) is_capital() bool {\n\tif s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) {\n\t\treturn false\n\t}\n\tfor i in 1 .. s.len {\n\t\tif s[i] >= `A` && s[i] <= `Z` {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// starts_with_capital returns `true`, if the first character in the string `s`,\n// is a capital letter, even if the rest are not.\n// Example: assert 'Hello'.starts_with_capital() == true\n// Example: assert 'Hello. World.'.starts_with_capital() == true\n@[direct_array_access]\npub fn (s string) starts_with_capital() bool {\n\tif s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) {\n\t\treturn false\n\t}\n\treturn true\n}\n\n// title returns the string with each word capitalized.\n// Example: assert 'hello v developer'.title() == 'Hello V Developer'\npub fn (s string) title() string {\n\twords := s.split(' ')\n\tmut tit := []string{}\n\tfor word in words {\n\t\ttit << word.capitalize()\n\t}\n\ttitle := tit.join(' ')\n\treturn title\n}\n\n// is_title returns true if all words of the string are capitalized.\n// Example: assert 'Hello V Developer'.is_title() == true\npub fn (s string) is_title() bool {\n\twords := s.split(' ')\n\tfor word in words {\n\t\tif !word.is_capital() {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// find_between returns the string found between `start` string and `end` string.\n// Example: assert 'hey [man] how you doin'.find_between('[', ']') == 'man'\npub fn (s string) find_between(start string, end string) string {\n\tstart_pos := s.index_(start)\n\tif start_pos == -1 {\n\t\treturn ''\n\t}\n\t// First get everything to the right of 'start'\n\tval := s[start_pos + start.len..]\n\tend_pos := val.index_(end)\n\tif end_pos == -1 {\n\t\treturn val\n\t}\n\treturn val[..end_pos]\n}\n\n// trim_space strips any of ` `, `\\n`, `\\t`, `\\v`, `\\f`, `\\r` from the start and end of the string.\n// Example: assert ' Hello V '.trim_space() == 'Hello V'\n@[inline]\npub fn (s string) trim_space() string {\n\treturn s.trim(' \\n\\t\\v\\f\\r')\n}\n\n// trim strips any of the characters given in `cutset` from the start and end of the string.\n// Example: assert ' ffHello V ffff'.trim(' f') == 'Hello V'\npub fn (s string) trim(cutset string) string {\n\tif s.len < 1 || cutset.len < 1 {\n\t\treturn s.clone()\n\t}\n\tleft, right := s.trim_indexes(cutset)\n\treturn s.substr(left, right)\n}\n\n// trim_indexes gets the new start and end indices of a string when any of the characters given in `cutset` were stripped from the start and end of the string. Should be used as an input to `substr()`. If the string contains only the characters in `cutset`, both values returned are zero.\n// Example: left, right := '-hi-'.trim_indexes('-')\n@[direct_array_access]\npub fn (s string) trim_indexes(cutset string) (int, int) {\n\tmut pos_left := 0\n\tmut pos_right := s.len - 1\n\tmut cs_match := true\n\tfor pos_left <= s.len && pos_right >= -1 && cs_match {\n\t\tcs_match = false\n\t\tfor cs in cutset {\n\t\t\tif s[pos_left] == cs {\n\t\t\t\tpos_left++\n\t\t\t\tcs_match = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfor cs in cutset {\n\t\t\tif s[pos_right] == cs {\n\t\t\t\tpos_right--\n\t\t\t\tcs_match = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif pos_left > pos_right {\n\t\t\treturn 0, 0\n\t\t}\n\t}\n\treturn pos_left, pos_right + 1\n}\n\n// trim_left strips any of the characters given in `cutset` from the left of the string.\n// Example: assert 'd Hello V developer'.trim_left(' d') == 'Hello V developer'\n@[direct_array_access]\npub fn (s string) trim_left(cutset string) string {\n\tif s.len < 1 || cutset.len < 1 {\n\t\treturn s.clone()\n\t}\n\tmut pos := 0\n\tfor pos < s.len {\n\t\tmut found := false\n\t\tfor cs in cutset {\n\t\t\tif s[pos] == cs {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tbreak\n\t\t}\n\t\tpos++\n\t}\n\treturn s[pos..]\n}\n\n// trim_right strips any of the characters given in `cutset` from the right of the string.\n// Example: assert ' Hello V d'.trim_right(' d') == ' Hello V'\n@[direct_array_access]\npub fn (s string) trim_right(cutset string) string {\n\tif s.len < 1 || cutset.len < 1 {\n\t\treturn s.clone()\n\t}\n\tmut pos := s.len - 1\n\tfor pos >= 0 {\n\t\tmut found := false\n\t\tfor cs in cutset {\n\t\t\tif s[pos] == cs {\n\t\t\t\tfound = true\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tbreak\n\t\t}\n\t\tpos--\n\t}\n\tif pos < 0 {\n\t\treturn ''\n\t}\n\treturn s[..pos + 1]\n}\n\n// trim_string_left strips `str` from the start of the string.\n// Example: assert 'WorldHello V'.trim_string_left('World') == 'Hello V'\npub fn (s string) trim_string_left(str string) string {\n\tif s.starts_with(str) {\n\t\treturn s[str.len..]\n\t}\n\treturn s.clone()\n}\n\n// trim_string_right strips `str` from the end of the string.\n// Example: assert 'Hello VWorld'.trim_string_right('World') == 'Hello V'\npub fn (s string) trim_string_right(str string) string {\n\tif s.ends_with(str) {\n\t\treturn s[..s.len - str.len]\n\t}\n\treturn s.clone()\n}\n\n// compare_strings returns `-1` if `a < b`, `1` if `a > b` else `0`.\npub fn compare_strings(a &string, b &string) int {\n\tif a < b {\n\t\treturn -1\n\t}\n\tif a > b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\n// compare_strings_by_len returns `-1` if `a.len < b.len`, `1` if `a.len > b.len` else `0`.\nfn compare_strings_by_len(a &string, b &string) int {\n\tif a.len < b.len {\n\t\treturn -1\n\t}\n\tif a.len > b.len {\n\t\treturn 1\n\t}\n\treturn 0\n}\n\n// compare_lower_strings returns the same as compare_strings but converts `a` and `b` to lower case before comparing.\nfn compare_lower_strings(a &string, b &string) int {\n\taa := a.to_lower()\n\tbb := b.to_lower()\n\treturn compare_strings(&aa, &bb)\n}\n\n// sort_ignore_case sorts the string array using case insensitive comparing.\n@[inline]\npub fn (mut s []string) sort_ignore_case() {\n\ts.sort_with_compare(compare_lower_strings)\n}\n\n// sort_by_len sorts the string array by each string's `.len` length.\n@[inline]\npub fn (mut s []string) sort_by_len() {\n\ts.sort_with_compare(compare_strings_by_len)\n}\n\n// str returns a copy of the string\n@[inline]\npub fn (s string) str() string {\n\treturn s.clone()\n}\n\n// at returns the byte at index `idx`.\n// Example: assert 'ABC'.at(1) == u8(`B`)\nfn (s string) at(idx int) u8 {\n\t$if !no_bounds_checking {\n\t\tif idx < 0 || idx >= s.len {\n\t\t\tpanic('string index out of range: ${idx} / ${s.len}')\n\t\t}\n\t}\n\treturn unsafe { s.str[idx] }\n}\n\n// version of `at()` that is used in `a[i] or {`\n// return an error when the index is out of range\nfn (s string) at_with_check(idx int) ?u8 {\n\tif idx < 0 || idx >= s.len {\n\t\treturn none\n\t}\n\tunsafe {\n\t\treturn s.str[idx]\n\t}\n}\n\n// Check if a string is an octal value. Returns 'true' if it is, or 'false' if it is not\n@[direct_array_access]\npub fn (str string) is_oct() bool {\n\tmut i := 0\n\n\tif str.len == 0 {\n\t\treturn false\n\t}\n\n\tif str[i] == `0` {\n\t\ti++\n\t} else if str[i] == `-` || str[i] == `+` {\n\t\ti++\n\n\t\tif str[i] == `0` {\n\t\t\ti++\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\treturn false\n\t}\n\n\tif str[i] == `o` {\n\t\ti++\n\t} else {\n\t\treturn false\n\t}\n\n\tif i == str.len {\n\t\treturn false\n\t}\n\n\tfor i < str.len {\n\t\tif str[i] < `0` || str[i] > `7` {\n\t\t\treturn false\n\t\t}\n\t\ti++\n\t}\n\n\treturn true\n}\n\n// is_bin returns `true` if the string is a binary value.\n@[direct_array_access]\npub fn (str string) is_bin() bool {\n\tmut i := 0\n\n\tif str.len == 0 {\n\t\treturn false\n\t}\n\n\tif str[i] == `0` {\n\t\ti++\n\t} else if str[i] == `-` || str[i] == `+` {\n\t\ti++\n\n\t\tif str[i] == `0` {\n\t\t\ti++\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\treturn false\n\t}\n\n\tif str[i] == `b` {\n\t\ti++\n\t} else {\n\t\treturn false\n\t}\n\n\tif i == str.len {\n\t\treturn false\n\t}\n\n\tfor i < str.len {\n\t\tif str[i] < `0` || str[i] > `1` {\n\t\t\treturn false\n\t\t}\n\t\ti++\n\t}\n\n\treturn true\n}\n\n// is_hex returns 'true' if the string is a hexadecimal value.\n@[direct_array_access]\npub fn (str string) is_hex() bool {\n\tmut i := 0\n\n\tif str.len == 0 {\n\t\treturn false\n\t}\n\n\tif str[i] == `0` {\n\t\ti++\n\t} else if str[i] == `-` || str[i] == `+` {\n\t\ti++\n\n\t\tif str[i] == `0` {\n\t\t\ti++\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\treturn false\n\t}\n\n\tif str[i] == `x` {\n\t\ti++\n\t} else {\n\t\treturn false\n\t}\n\n\tif i == str.len {\n\t\treturn false\n\t}\n\n\tfor i < str.len {\n\t\tif (str[i] < `0` || str[i] > `9`) && ((str[i] < `a` || str[i] > `f`)\n\t\t\t&& (str[i] < `A` || str[i] > `F`)) {\n\t\t\treturn false\n\t\t}\n\t\ti++\n\t}\n\n\treturn true\n}\n\n// Check if a string is an integer value. Returns 'true' if it is, or 'false' if it is not\n@[direct_array_access]\npub fn (str string) is_int() bool {\n\tmut i := 0\n\n\tif str.len == 0 {\n\t\treturn false\n\t}\n\n\tif (str[i] != `-` && str[i] != `+`) && (!str[i].is_digit()) {\n\t\treturn false\n\t} else {\n\t\ti++\n\t}\n\n\tif i == str.len && (!str[i - 1].is_digit()) {\n\t\treturn false\n\t}\n\n\tfor i < str.len {\n\t\tif str[i] < `0` || str[i] > `9` {\n\t\t\treturn false\n\t\t}\n\t\ti++\n\t}\n\n\treturn true\n}\n\n// is_space returns `true` if the byte is a white space character.\n// The following list is considered white space characters: ` `, `\\t`, `\\n`, `\\v`, `\\f`, `\\r`, 0x85, 0xa0\n// Example: assert u8(` `).is_space() == true\n@[inline]\npub fn (c u8) is_space() bool {\n\t// 0x85 is NEXT LINE (NEL)\n\t// 0xa0 is NO-BREAK SPACE\n\treturn c == 32 || (c > 8 && c < 14) || c == 0x85 || c == 0xa0\n}\n\n// is_digit returns `true` if the byte is in range 0-9 and `false` otherwise.\n// Example: assert u8(`9`).is_digit() == true\n@[inline]\npub fn (c u8) is_digit() bool {\n\treturn c >= `0` && c <= `9`\n}\n\n// is_hex_digit returns `true` if the byte is either in range 0-9, a-f or A-F and `false` otherwise.\n// Example: assert u8(`F`).is_hex_digit() == true\n@[inline]\npub fn (c u8) is_hex_digit() bool {\n\treturn (c >= `0` && c <= `9`) || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`)\n}\n\n// is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise.\n// Example: assert u8(`7`).is_oct_digit() == true\n@[inline]\npub fn (c u8) is_oct_digit() bool {\n\treturn c >= `0` && c <= `7`\n}\n\n// is_bin_digit returns `true` if the byte is a binary digit (0 or 1) and `false` otherwise.\n// Example: assert u8(`0`).is_bin_digit() == true\n@[inline]\npub fn (c u8) is_bin_digit() bool {\n\treturn c == `0` || c == `1`\n}\n\n// is_letter returns `true` if the byte is in range a-z or A-Z and `false` otherwise.\n// Example: assert u8(`V`).is_letter() == true\n@[inline]\npub fn (c u8) is_letter() bool {\n\treturn (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`)\n}\n\n// is_alnum returns `true` if the byte is in range a-z, A-Z, 0-9 and `false` otherwise.\n// Example: assert u8(`V`).is_alnum() == true\n@[inline]\npub fn (c u8) is_alnum() bool {\n\treturn (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`)\n}\n\n// free allows for manually freeing the memory occupied by the string\n@[manualfree; unsafe]\npub fn (s &string) free() {\n\t$if prealloc {\n\t\treturn\n\t}\n\tif s.is_lit == -98761234 {\n\t\tdouble_free_msg := unsafe { &u8(c'double string.free() detected\\n') }\n\t\tdouble_free_msg_len := unsafe { vstrlen(double_free_msg) }\n\t\t$if freestanding {\n\t\t\tbare_eprint(double_free_msg, u64(double_free_msg_len))\n\t\t} $else {\n\t\t\t_write_buf_to_fd(1, double_free_msg, double_free_msg_len)\n\t\t}\n\t\treturn\n\t}\n\tif s.is_lit == 1 || s.str == 0 {\n\t\treturn\n\t}\n\tunsafe {\n\t\t// C.printf(c's: %x %s\\n', s.str, s.str)\n\t\tfree(s.str)\n\t\ts.str = nil\n\t}\n\ts.is_lit = -98761234\n}\n\n// before returns the contents before `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.before('.') == '23:34:45'\n// Example: assert 'abcd'.before('.') == 'abcd'\n// TODO: deprecate and remove either .before or .all_before\npub fn (s string) before(sub string) string {\n\tpos := s.index_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[..pos]\n}\n\n// all_before returns the contents before `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.all_before('.') == '23:34:45'\n// Example: assert 'abcd'.all_before('.') == 'abcd'\npub fn (s string) all_before(sub string) string {\n\t// TODO remove dup method\n\tpos := s.index_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[..pos]\n}\n\n// all_before_last returns the contents before the last occurrence of `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.all_before_last(':') == '23:34'\n// Example: assert 'abcd'.all_before_last('.') == 'abcd'\npub fn (s string) all_before_last(sub string) string {\n\tpos := s.index_last_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[..pos]\n}\n\n// all_after returns the contents after `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.all_after('.') == '234'\n// Example: assert 'abcd'.all_after('z') == 'abcd'\npub fn (s string) all_after(sub string) string {\n\tpos := s.index_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[pos + sub.len..]\n}\n\n// all_after_last returns the contents after the last occurrence of `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.all_after_last(':') == '45.234'\n// Example: assert 'abcd'.all_after_last('z') == 'abcd'\npub fn (s string) all_after_last(sub string) string {\n\tpos := s.index_last_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[pos + sub.len..]\n}\n\n// all_after_first returns the contents after the first occurrence of `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.all_after_first(':') == '34:45.234'\n// Example: assert 'abcd'.all_after_first('z') == 'abcd'\npub fn (s string) all_after_first(sub string) string {\n\tpos := s.index_(sub)\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[pos + sub.len..]\n}\n\n// after returns the contents after the last occurrence of `sub` in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.after(':') == '45.234'\n// Example: assert 'abcd'.after('z') == 'abcd'\n// TODO: deprecate either .all_after_last or .after\n@[inline]\npub fn (s string) after(sub string) string {\n\treturn s.all_after_last(sub)\n}\n\n// after_char returns the contents after the first occurrence of `sub` character in the string.\n// If the substring is not found, it returns the full input string.\n// Example: assert '23:34:45.234'.after_char(`:`) == '34:45.234'\n// Example: assert 'abcd'.after_char(`:`) == 'abcd'\npub fn (s string) after_char(sub u8) string {\n\tmut pos := -1\n\tfor i, c in s {\n\t\tif c == sub {\n\t\t\tpos = i\n\t\t\tbreak\n\t\t}\n\t}\n\tif pos == -1 {\n\t\treturn s.clone()\n\t}\n\treturn s[pos + 1..]\n}\n\n// join joins a string array into a string using `sep` separator.\n// Example: assert ['Hello','V'].join(' ') == 'Hello V'\npub fn (a []string) join(sep string) string {\n\tif a.len == 0 {\n\t\treturn ''\n\t}\n\tmut len := 0\n\tfor val in a {\n\t\tlen += val.len + sep.len\n\t}\n\tlen -= sep.len\n\t// Allocate enough memory\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(len + 1) }\n\t\tlen: len\n\t}\n\tmut idx := 0\n\tfor i, val in a {\n\t\tunsafe {\n\t\t\tvmemcpy(voidptr(res.str + idx), val.str, val.len)\n\t\t\tidx += val.len\n\t\t}\n\t\t// Add sep if it's not last\n\t\tif i != a.len - 1 {\n\t\t\tunsafe {\n\t\t\t\tvmemcpy(voidptr(res.str + idx), sep.str, sep.len)\n\t\t\t\tidx += sep.len\n\t\t\t}\n\t\t}\n\t}\n\tunsafe {\n\t\tres.str[res.len] = 0\n\t}\n\treturn res\n}\n\n// join joins a string array into a string using a `\\n` newline delimiter.\n@[inline]\npub fn (s []string) join_lines() string {\n\treturn s.join('\\n')\n}\n\n// reverse returns a reversed string.\n// Example: assert 'Hello V'.reverse() == 'V olleH'\n@[direct_array_access]\npub fn (s string) reverse() string {\n\tif s.len == 0 || s.len == 1 {\n\t\treturn s.clone()\n\t}\n\tmut res := string{\n\t\tstr: unsafe { malloc_noscan(s.len + 1) }\n\t\tlen: s.len\n\t}\n\tfor i := s.len - 1; i >= 0; i-- {\n\t\tunsafe {\n\t\t\tres.str[s.len - i - 1] = s[i]\n\t\t}\n\t}\n\tunsafe {\n\t\tres.str[res.len] = 0\n\t}\n\treturn res\n}\n\n// limit returns a portion of the string, starting at `0` and extending for a given number of characters afterward.\n// 'hello'.limit(2) => 'he'\n// 'hi'.limit(10) => 'hi'\npub fn (s string) limit(max int) string {\n\tu := s.runes()\n\tif u.len <= max {\n\t\treturn s.clone()\n\t}\n\treturn u[0..max].string()\n}\n\n// hash returns an integer hash of the string.\npub fn (s string) hash() int {\n\tmut h := u32(0)\n\tif h == 0 && s.len > 0 {\n\t\tfor c in s {\n\t\t\th = h * 31 + u32(c)\n\t\t}\n\t}\n\treturn int(h)\n}\n\n// bytes returns the string converted to a byte array.\npub fn (s string) bytes() []u8 {\n\tif s.len == 0 {\n\t\treturn []\n\t}\n\tmut buf := []u8{len: s.len}\n\tunsafe { vmemcpy(buf.data, s.str, s.len) }\n\treturn buf\n}\n\n// repeat returns a new string with `count` number of copies of the string it was called on.\n@[direct_array_access]\npub fn (s string) repeat(count int) string {\n\tif count < 0 {\n\t\tpanic('string.repeat: count is negative: ${count}')\n\t} else if count == 0 {\n\t\treturn ''\n\t} else if count == 1 {\n\t\treturn s.clone()\n\t}\n\tmut ret := unsafe { malloc_noscan(s.len * count + 1) }\n\tfor i in 0 .. count {\n\t\tunsafe {\n\t\t\tvmemcpy(ret + i * s.len, s.str, s.len)\n\t\t}\n\t}\n\tnew_len := s.len * count\n\tunsafe {\n\t\tret[new_len] = 0\n\t}\n\treturn unsafe { ret.vstring_with_len(new_len) }\n}\n\n// fields returns a string array of the string split by `\\t` and ` `\n// Example: assert '\\t\\tv = v'.fields() == ['v', '=', 'v']\n// Example: assert '  sss   ssss'.fields() == ['sss', 'ssss']\npub fn (s string) fields() []string {\n\tmut res := []string{}\n\tmut word_start := 0\n\tmut word_len := 0\n\tmut is_in_word := false\n\tmut is_space := false\n\tfor i, c in s {\n\t\tis_space = c in [32, 9, 10]\n\t\tif !is_space {\n\t\t\tword_len++\n\t\t}\n\t\tif !is_in_word && !is_space {\n\t\t\tword_start = i\n\t\t\tis_in_word = true\n\t\t\tcontinue\n\t\t}\n\t\tif is_space && is_in_word {\n\t\t\tres << s[word_start..word_start + word_len]\n\t\t\tis_in_word = false\n\t\t\tword_len = 0\n\t\t\tword_start = 0\n\t\t\tcontinue\n\t\t}\n\t}\n\tif is_in_word && word_len > 0 {\n\t\t// collect the remainder word at the end\n\t\tres << s[word_start..s.len]\n\t}\n\treturn res\n}\n\n// strip_margin allows multi-line strings to be formatted in a way that removes white-space\n// before a delimiter. By default `|` is used.\n// Note: the delimiter has to be a byte at this time. That means surrounding\n// the value in ``.\n//\n// See also: string.trim_indent()\n//\n// Example:\n// ```v\n// st := 'Hello there,\n//        |  this is a string,\n//        |  Everything before the first | is removed'.strip_margin()\n//\n// assert st == 'Hello there,\n//   this is a string,\n//   Everything before the first | is removed'\n// ```\n@[inline]\npub fn (s string) strip_margin() string {\n\treturn s.strip_margin_custom(`|`)\n}\n\n// strip_margin_custom does the same as `strip_margin` but will use `del` as delimiter instead of `|`\n@[direct_array_access]\npub fn (s string) strip_margin_custom(del u8) string {\n\tmut sep := del\n\tif sep.is_space() {\n\t\tprintln('Warning: `strip_margin` cannot use white-space as a delimiter')\n\t\tprintln('    Defaulting to `|`')\n\t\tsep = `|`\n\t}\n\t// don't know how much space the resulting string will be, but the max it\n\t// can be is this big\n\tmut ret := unsafe { malloc_noscan(s.len + 1) }\n\tmut count := 0\n\tfor i := 0; i < s.len; i++ {\n\t\tif s[i] in [10, 13] {\n\t\t\tunsafe {\n\t\t\t\tret[count] = s[i]\n\t\t\t}\n\t\t\tcount++\n\t\t\t// CRLF\n\t\t\tif s[i] == 13 && i < s.len - 1 && s[i + 1] == 10 {\n\t\t\t\tunsafe {\n\t\t\t\t\tret[count] = s[i + 1]\n\t\t\t\t}\n\t\t\t\tcount++\n\t\t\t\ti++\n\t\t\t}\n\t\t\tfor s[i] != sep {\n\t\t\t\ti++\n\t\t\t\tif i >= s.len {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tunsafe {\n\t\t\t\tret[count] = s[i]\n\t\t\t}\n\t\t\tcount++\n\t\t}\n\t}\n\tunsafe {\n\t\tret[count] = 0\n\t\treturn ret.vstring_with_len(count)\n\t}\n}\n\n// trim_indent detects a common minimal indent of all the input lines,\n// removes it from every line and also removes the first and the last\n// lines if they are blank (notice difference blank vs empty).\n//\n// Note that blank lines do not affect the detected indent level.\n//\n// In case if there are non-blank lines with no leading whitespace characters\n// (no indent at all) then the common indent is 0, and therefore this function\n// doesn't change the indentation.\n//\n// Example:\n// ```v\n// st := '\n//      Hello there,\n//      this is a string,\n//      all the leading indents are removed\n//      and also the first and the last lines if they are blank\n// '.trim_indent()\n//\n// assert st == 'Hello there,\n// this is a string,\n// all the leading indents are removed\n// and also the first and the last lines if they are blank'\n// ```\npub fn (s string) trim_indent() string {\n\tmut lines := s.split_into_lines()\n\n\tlines_indents := lines\n\t\t.filter(!it.is_blank())\n\t\t.map(it.indent_width())\n\n\tmut min_common_indent := int(max_int) // max int\n\tfor line_indent in lines_indents {\n\t\tif line_indent < min_common_indent {\n\t\t\tmin_common_indent = line_indent\n\t\t}\n\t}\n\n\t// trim first line if it's blank\n\tif lines.len > 0 && lines.first().is_blank() {\n\t\tlines = unsafe { lines[1..] }\n\t}\n\n\t// trim last line if it's blank\n\tif lines.len > 0 && lines.last().is_blank() {\n\t\tlines = unsafe { lines[..lines.len - 1] }\n\t}\n\n\tmut trimmed_lines := []string{cap: lines.len}\n\n\tfor line in lines {\n\t\tif line.is_blank() {\n\t\t\ttrimmed_lines << line\n\t\t\tcontinue\n\t\t}\n\n\t\ttrimmed_lines << line[min_common_indent..]\n\t}\n\n\treturn trimmed_lines.join('\\n')\n}\n\n// indent_width returns the number of spaces or tabs at the beginning of the string.\n// Example: assert '  v'.indent_width() == 2\n// Example: assert '\\t\\tv'.indent_width() == 2\npub fn (s string) indent_width() int {\n\tfor i, c in s {\n\t\tif !c.is_space() {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn 0\n}\n\n// is_blank returns true if the string is empty or contains only white-space.\n// Example: assert ' '.is_blank()\n// Example: assert '\\t'.is_blank()\n// Example: assert 'v'.is_blank() == false\npub fn (s string) is_blank() bool {\n\tif s.len == 0 {\n\t\treturn true\n\t}\n\n\tfor c in s {\n\t\tif !c.is_space() {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// match_glob matches the string, with a Unix shell-style wildcard pattern.\n// Note: wildcard patterns are NOT the same as regular expressions.\n//   They are much simpler, and do not allow backtracking, captures, etc.\n//   The special characters used in shell-style wildcards are:\n// `*` - matches everything\n// `?` - matches any single character\n// `[seq]` - matches any of the characters in the sequence\n// `[^seq]` - matches any character that is NOT in the sequence\n//   Any other character in `pattern`, is matched 1:1 to the corresponding\n// character in `name`, including / and \\.\n//   You can wrap the meta-characters in brackets too, i.e. `[?]` matches `?`\n// in the string, and `[*]` matches `*` in the string.\n// Example: assert 'ABCD'.match_glob('AB*')\n// Example: assert 'ABCD'.match_glob('*D')\n// Example: assert 'ABCD'.match_glob('*B*')\n// Example: assert !'ABCD'.match_glob('AB')\n@[direct_array_access]\npub fn (name string) match_glob(pattern string) bool {\n\t// Initial port based on https://research.swtch.com/glob.go\n\t// See also https://research.swtch.com/glob\n\tmut px := 0\n\tmut nx := 0\n\tmut next_px := 0\n\tmut next_nx := 0\n\tplen := pattern.len\n\tnlen := name.len\n\tfor px < plen || nx < nlen {\n\t\tif px < plen {\n\t\t\tc := pattern[px]\n\t\t\tmatch c {\n\t\t\t\t`?` {\n\t\t\t\t\t// single-character wildcard\n\t\t\t\t\tif nx < nlen {\n\t\t\t\t\t\tpx++\n\t\t\t\t\t\tnx++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t`*` {\n\t\t\t\t\t// zero-or-more-character wildcard\n\t\t\t\t\t// Try to match at nx.\n\t\t\t\t\t// If that doesn't work out, restart at nx+1 next.\n\t\t\t\t\tnext_px = px\n\t\t\t\t\tnext_nx = nx + 1\n\t\t\t\t\tpx++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t`[` {\n\t\t\t\t\tif nx < nlen {\n\t\t\t\t\t\twanted_c := name[nx]\n\t\t\t\t\t\tmut bstart := px\n\t\t\t\t\t\tmut is_inverted := false\n\t\t\t\t\t\tmut inner_match := false\n\t\t\t\t\t\tmut inner_idx := bstart + 1\n\t\t\t\t\t\tmut inner_c := 0\n\t\t\t\t\t\tif inner_idx < plen {\n\t\t\t\t\t\t\tinner_c = pattern[inner_idx]\n\t\t\t\t\t\t\tif inner_c == `^` {\n\t\t\t\t\t\t\t\tis_inverted = true\n\t\t\t\t\t\t\t\tinner_idx++\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor ; inner_idx < plen; inner_idx++ {\n\t\t\t\t\t\t\tinner_c = pattern[inner_idx]\n\t\t\t\t\t\t\tif inner_c == `]` {\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif inner_c == wanted_c {\n\t\t\t\t\t\t\t\tinner_match = true\n\t\t\t\t\t\t\t\tfor px < plen && pattern[px] != `]` {\n\t\t\t\t\t\t\t\t\tpx++\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif is_inverted {\n\t\t\t\t\t\t\tif inner_match {\n\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tpx = inner_idx\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpx++\n\t\t\t\t\tnx++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// an ordinary character\n\t\t\t\t\tif nx < nlen && name[nx] == c {\n\t\t\t\t\t\tpx++\n\t\t\t\t\t\tnx++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif 0 < next_nx && next_nx <= nlen {\n\t\t\t// A mismatch, try restarting:\n\t\t\tpx = next_px\n\t\t\tnx = next_nx\n\t\t\tcontinue\n\t\t}\n\t\treturn false\n\t}\n\t// Matched all of `pattern` to all of `name`\n\treturn true\n}\n\n// is_ascii returns true  if all characters belong to the US-ASCII set ([` `..`~`])\n@[inline]\npub fn (s string) is_ascii() bool {\n\treturn !s.bytes().any(it < u8(` `) || it > u8(`~`))\n}\n"
  },
  {
    "path": "src/tests/testdata/documentation/rendered.vv",
    "content": "module documentation\n\n// has checks if the enum value has the passed flag.\n//\n// **bold**\n// *italic*\n// `code`\n// [link](https://github.com)\n// ---\n//\n// # Heading 1\n// ## Heading 2\n// ### Heading 3\n//\n// line break.\n// line break!\n// line break?\n//\n// Example:\n// ```\n// [flag]\n// enum Permissions {\n//   read  // = 0b0001\n//   write // = 0b0010\n//   other // = 0b0100\n// }\n//\n// fn main() {\n//   p := Permissions.read\n//   assert p.has(.read) // test if p has read flag\n//   assert p.has(.read | .other) // test if *at least one* of the flags is set\n// }\n// ```\n//\n// Example: println('inline example')\nfn f/*caret*/oo() {\n}\n"
  },
  {
    "path": "src/tests/testdata/documentation/rendered.vv.md",
    "content": "Module: **documentation**\n```v\nfn foo()\n```\n\nhas checks if the enum value has the passed flag.\n **bold** *italic* `code` [link](https://github.com) \n\n # Heading 1\n## Heading 2\n### Heading 3\n line break.\nline break!\nline break?\n \nExample:\n\n```\n[flag]\nenum Permissions {\n  read  // = 0b0001\n  write // = 0b0010\n  other // = 0b0100\n}\n\nfn main() {\n  p := Permissions.read\n  assert p.has(.read) // test if p has read flag\n  assert p.has(.read | .other) // test if *at least one* of the flags is set\n}\n```\n \n\nExample:\n```\nprintln('inline example')\n```\n\n"
  },
  {
    "path": "src/tests/testdata/documentation/stubs.vv",
    "content": "type Foo = v/*caret*/oidptr\n\n"
  },
  {
    "path": "src/tests/testdata/documentation/stubs.vv.md",
    "content": "Module: **stubs**\n```v\npub type voidptr = voidptr\n```\n\nvoidptr is an untyped pointer. You can pass any other type of pointer value, to a function that accepts a voidptr.\nMostly used for [C interoperability](https://docs.vosca.dev/advanced-concepts/v-and-c.html).\n"
  },
  {
    "path": "src/tests/testdata/types/bool_operators.vv",
    "content": "module types\n\nexpr_type(1 in [], 'bool')\nexpr_type(1 !in [], 'bool')\nexpr_type(1 is Foo, 'bool')\nexpr_type(1 !is Foo, 'bool')\nexpr_type(1 == 1, 'bool')\nexpr_type(1 != 1, 'bool')\nexpr_type(1 > 1, 'bool')\nexpr_type(1 >= 1, 'bool')\nexpr_type(1 < 1, 'bool')\nexpr_type(1 <= 1, 'bool')\nexpr_type(true && false, 'bool')\nexpr_type(true || false, 'bool')\nexpr_type(!false, 'bool')\n\nexpr_type(select {\n\ta := <-ch {}\n}, 'bool')\n"
  },
  {
    "path": "src/tests/testdata/types/call_expression.vv",
    "content": "module types\n\nstruct FooBar {\n}\n\nfn some_foo() string {}\n\nfn foo_int() int {}\n\nfn get_foo_bar() FooBar {}\n\nfn main() {\n\texpr_type(some_foo(), 'string')\n\texpr_type(foo_int(), 'int')\n\texpr_type(get_foo_bar(), 'types.FooBar')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/chan_type.vv",
    "content": "module types\n\nfn main() {\n\tch := chan int{}\n\texpr_type(ch, 'chan int')\n\texpr_type(<-ch, 'int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/constants.vv",
    "content": "module types\n\nconst simple = 1\nconst string_array = ['hello', 'world']\n\nfn main() {\n\texpr_type(types.simple, 'int')\n\texpr_type(types.string_array, '[]string')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/fields.vv",
    "content": "module types\n\nstruct FieldsFoo {\n\tname  string\n\tparts []int\n\tcb    fn () string\n}\n\nfn main() {\n\tfoo := FieldsFoo{\n\t\tname: 'foo'\n\t\tparts: [1, 2, 3]\n\t}\n\n\texpr_type(foo.name, 'string')\n\texpr_type(foo.parts, '[]int')\n\texpr_type(foo.cb, 'fn () string')\n\texpr_type(foo.cb(), 'string')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/for_loop.vv",
    "content": "module types\n\nfor i in 0 .. 10 {\n\texpr_type(i, 'int')\n}\n\narr := ['str']\n\nfor val in arr {\n\texpr_type(val, 'string')\n}\n\nfor i, val in arr {\n\texpr_type(i, 'int')\n\texpr_type(val, 'string')\n}\n\nfixed_arr := ['str']!\nexpr_type(fixed_arr, '[1]string')\n\nfor val in fixed_arr {\n\texpr_type(val, 'string')\n}\n\nfor i, val in fixed_arr {\n\texpr_type(i, 'int')\n\texpr_type(val, 'string')\n}\n\nmp := map[string]int{}\n\nfor key, val in mp {\n\texpr_type(key, 'string')\n\texpr_type(val, 'int')\n}\n\ntype MyMap = map[string]int\n\nmp2 := MyMap{}\n\nfor key, val in mp2 {\n\texpr_type(key, 'string')\n\texpr_type(val, 'int')\n}\n\nfor val in 'hello' {\n\texpr_type(val, 'u8')\n}\n\nstruct Iterator {}\n\nfn (mut i Iterator) next() ?int {\n\treturn 1\n}\n\nit := Iterator{}\nfor val in it {\n\texpr_type(val, 'int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/for_loops.vv",
    "content": "module types\n\nfn arrays() {\n\tfor index in 0 .. 10 {\n\t\texpr_type(index, 'int')\n\t}\n\n\tint_array := [1, 2, 3]\n\n\tfor index in int_array {\n\t\texpr_type(index, 'int')\n\t}\n\n\tfor index, value in int_array {\n\t\texpr_type(index, 'int')\n\t\texpr_type(value, 'int')\n\t}\n\n\tstring_array := ['1', '2', '3']\n\n\tfor index in string_array {\n\t\texpr_type(index, 'string')\n\t}\n\n\tfor index, value in string_array {\n\t\texpr_type(index, 'int')\n\t\texpr_type(value, 'string')\n\t}\n\n\tbool_array := [true, false]\n\n\tfor index in bool_array {\n\t\texpr_type(index, 'bool')\n\t}\n\n\tfor index, value in bool_array {\n\t\texpr_type(index, 'int')\n\t\texpr_type(value, 'bool')\n\t}\n}\n\nfn maps() {\n\tmp := map[string]int{}\n\n\tfor key, value in mp {\n\t\texpr_type(key, 'string')\n\t\texpr_type(value, 'int')\n\t}\n}\n\nfn strings() {\n\tmp := ''\n\n\tfor value in mp {\n\t\texpr_type(value, 'u8')\n\t}\n\n\tfor key, value in mp {\n\t\texpr_type(key, 'int')\n\t\texpr_type(value, 'u8')\n\t}\n}\n"
  },
  {
    "path": "src/tests/testdata/types/function_literal.vv",
    "content": "module types\n\nfn types_foo(a string) string {}\n\nfn types_foo1(a string) (int, string) {}\n\nfn types_foo2(a string, b int) (int, string) {}\n\nfn types_foo3(a string, b int) {}\n\nfn types_foo4() {}\n\nfn main() {\n\texpr_type(types_foo, 'fn (string) string')\n\texpr_type(types_foo1, 'fn (string) (int, string)')\n\texpr_type(types_foo2, 'fn (string, int) (int, string)')\n\texpr_type(types_foo3, 'fn (string, int)')\n\texpr_type(types_foo4, 'fn ()')\n\n\texpr_type(fn () {}, 'fn ()')\n\texpr_type(fn (i int) {}, 'fn (int)')\n\texpr_type(fn (i int) string {}, 'fn (int) string')\n\texpr_type(fn (i int, s string) string {}, 'fn (int, string) string')\n}\n\nfn calls() {\n\tfunc := fn (i int) string {}\n\texpr_type(func(), 'string')\n\n\tfunc1 := fn (i int) int {}\n\texpr_type(func1(), 'int')\n\n\tfunc2 := fn (i int) int {}()\n\texpr_type(func2, 'int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/generics.vv",
    "content": "module types\n\nstruct GenericStruct[T] {}\n\nfn GenericStruct.static_method[T]() string {\n\treturn 'hello'\n}\n\nfn main() {\n\texpr_type(GenericStruct[int]{}, 'types.GenericStruct[int]')\n\texpr_type(GenericStruct.static_method[string](), 'string')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/if_expression.vv",
    "content": "module types\n\nfn main() {\n\ta := if true {\n\t\t100\n\t} else {\n\t\t200\n\t}\n\texpr_type(a, 'int')\n\n\tb := if true {\n\t\t'100'\n\t} else {\n\t\t'200'\n\t}\n\texpr_type(b, 'string')\n\n\tc := if true {\n\t\tunsafe { 100 }\n\t} else {\n\t\t200\n\t}\n\texpr_type(c, 'int')\n\n\td := if true {\n\t\tinner := unsafe { 100 }\n\t\tinner\n\t} else {\n\t\t200\n\t}\n\texpr_type(d, 'int')\n\n\te := if true {\n\t\tinner := map[int]string{}\n\t\tinner[100]\n\t} else {\n\t\t200\n\t}\n\texpr_type(e, 'string')\n\n\tf := if true {\n\t\tunknown\n\t} else {\n\t\t200\n\t}\n\texpr_type(f, 'int')\n\n\tg := $if macos {\n\t\t1\n\t} $else {\n\t\t2\n\t}\n\texpr_type(g, 'int')\n}\n\nfn get_opt() ?int {\n\treturn 100\n}\n\nfn get_res() !int {\n\treturn 100\n}\n\nfn unwrapping() {\n\tif a := get_opt() {\n\t\texpr_type(a, 'int')\n\t}\n\n\tif a := get_res() {\n\t\texpr_type(a, 'int')\n\t}\n}\n"
  },
  {
    "path": "src/tests/testdata/types/json_decode.vv",
    "content": "module types\n\nimport json\n\nstruct JsonData {}\n\nfn main() {\n\tdata := ''\n\n\tres := json.decode(JsonData, data)\n\texpr_type(res, '!types.JsonData')\n\n\tres2 := json.decode([]JsonData, data)\n\texpr_type(res2, '![]types.JsonData')\n\n\tres3 := json.decode(map[string]JsonData, data)\n\texpr_type(res3, '!map[string]types.JsonData')\n\n\tif res4 := json.decode(map[string]JsonData, data) {\n\t\texpr_type(res4, 'map[string]types.JsonData')\n\t}\n}\n"
  },
  {
    "path": "src/tests/testdata/types/literals.vv",
    "content": "module types\n\nfn main() {\n\texpr_type(100, 'int')\n\texpr_type(3.14, 'f64')\n\texpr_type(`r`, 'rune')\n\texpr_type(true, 'bool')\n\texpr_type(false, 'bool')\n\texpr_type(nil, 'voidptr')\n\texpr_type(none, 'none')\n\texpr_type('hello', 'string')\n\texpr_type(r'raw hello', 'string')\n\texpr_type(c'c hello', '&u8')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/map_init_expression.vv",
    "content": "module types\n\nstruct Foo {}\n\nfn main() {\n\tmp1 := {\n\t\t0: 100\n\t}\n\texpr_type(mp1, 'map[int]int')\n\texpr_type(mp1[0], 'int')\n\n\tmp2 := {\n\t\t'0': 100\n\t}\n\texpr_type(mp2, 'map[string]int')\n\texpr_type(mp2[0], 'int')\n\n\tmp3 := {\n\t\t0: Foo{}\n\t}\n\texpr_type(mp3, 'map[int]types.Foo')\n\texpr_type(mp3[0], 'types.Foo')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/match_expression.vv",
    "content": "module types\n\nfn main() {\n\ta := match true {\n\t\tfalse { 100 }\n\t\telse { 100 }\n\t}\n\texpr_type(a, 'int')\n\n\tb := match true {\n\t\tfalse {\n\t\t\tinner := 100\n\t\t\tinner\n\t\t}\n\t\telse {\n\t\t\t100\n\t\t}\n\t}\n\texpr_type(b, 'int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/parameters.vv",
    "content": "module types\n\nstruct FooBar {}\n\nfn foo(param &FooBar, param2 []&FooBar) {\n\texpr_type(param, '&types.FooBar')\n\texpr_type(param2, '[]&types.FooBar')\n}\n\nfn foo2(variadic ...FooBar) {\n\texpr_type(variadic, '[]types.FooBar')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/pointers.vv",
    "content": "module types\n\nfn main() {\n\ta := 100\n\tb := &a\n\tc := &b\n\td := *c\n\te := *d\n\n\texpr_type(a, 'int')\n\texpr_type(b, '&int')\n\texpr_type(c, '&&int')\n\texpr_type(d, '&int')\n\texpr_type(e, 'int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/receiver.vv",
    "content": "module types\n\nstruct ReceiverFoo {}\n\nfn (r &ReceiverFoo) method() {\n\texpr_type(r, '&types.ReceiverFoo')\n\texpr_type(*r, 'types.ReceiverFoo')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/slice_and_index_expression.vv",
    "content": "module types\n\nfn main() {\n\tarr := [1, 2, 3]\n\texpr_type(arr[0], 'int')\n\texpr_type(arr[0..10], '[]int')\n\n\tfixed_arr := [1, 2, 3]!\n\texpr_type(fixed_arr[0], 'int')\n\texpr_type(fixed_arr[0..2], '[]int')\n\n\ts := 'string'\n\texpr_type(s[0], 'u8')\n\texpr_type(s[0..2], 'string')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/type_initializer.vv",
    "content": "module types\n\nstruct FooBar {\n}\n\nfn main() {\n\texpr_type(FooBar{}, 'types.FooBar')\n\texpr_type(&FooBar{}, '&types.FooBar')\n\texpr_type([]int{}, '[]int')\n\texpr_type([]&FooBar{}, '[]&types.FooBar')\n\texpr_type(map[string]int{}, 'map[string]int')\n}\n"
  },
  {
    "path": "src/tests/testdata/types/unsafe_expression.vv",
    "content": "module types\n\nexpr_type(unsafe { 100 }, 'int')\nexpr_type(unsafe {\n\ta := 100\n\ta\n}, 'int')\n"
  },
  {
    "path": "src/tests/types.v",
    "content": "module tests\n\nimport testing\n\nfn types() testing.Tester {\n\tmut t := testing.with_name('types')\n\n\tt.type_test('literals', 'types/literals.vv')\n\tt.type_test('parameters types', 'types/parameters.vv')\n\tt.type_test('call expressions', 'types/call_expression.vv')\n\tt.type_test('type initializer', 'types/type_initializer.vv')\n\tt.type_test('for loops', 'types/for_loops.vv')\n\tt.type_test('slice and index expression', 'types/slice_and_index_expression.vv')\n\tt.type_test('function literal', 'types/function_literal.vv')\n\tt.type_test('pointers', 'types/pointers.vv')\n\tt.type_test('bool operators', 'types/bool_operators.vv')\n\tt.type_test('unsafe expression', 'types/unsafe_expression.vv')\n\tt.type_test('if expression', 'types/if_expression.vv')\n\tt.type_test('match expression', 'types/match_expression.vv')\n\tt.type_test('map init expression', 'types/map_init_expression.vv')\n\tt.type_test('chan type', 'types/chan_type.vv')\n\tt.type_test('struct fields', 'types/fields.vv')\n\tt.type_test('receiver', 'types/receiver.vv')\n\tt.type_test('json decode', 'types/json_decode.vv')\n\tt.type_test('generics', 'types/generics.vv')\n\tt.type_test('constants', 'types/constants.vv')\n\tt.type_test('for loop', 'types/for_loop.vv')\n\n\treturn t\n}\n"
  },
  {
    "path": "src/tools/project-checker.v",
    "content": "module main\n\nimport math\nimport runtime\nimport sync\nimport os\nimport time\nimport src.analyzer.parser\nimport tree_sitter_v.bindings\n\nfn main() {\n\tmut checker := Checker{\n\t\troot: os.join_path(@VEXEROOT, 'vlib')\n\t}\n\tchecker.check()\n}\n\npub type AstNode = bindings.Node[bindings.NodeType]\n\nstruct ErrorInfo {\n\tpath string\n\tnode AstNode\n}\n\nfn (i ErrorInfo) str() string {\n\tcontent := os.read_file(i.path) or { return 'no content' }\n\n\tparent := i.node.parent() or { return 'no parent' }\n\ttext := parent.text(content)\n\n\tif parent.start_byte() == 0 {\n\t\treturn 'root'\n\t}\n\n\treturn '\n\nFound error at ${i.path}:${i.node.start_point().row}:${i.node.start_point().column}\n\nparent: ${parent}\nparent text: ${text}\n'\n}\n\nstruct Checker {\n\troot string\n}\n\nfn (mut _ Checker) need_check(path string) bool {\n\tif !path.ends_with('.v') {\n\t\treturn false\n\t}\n\n\tif path.contains('stubs/') {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\npub fn (mut i Checker) check() {\n\tnow := time.now()\n\tprintln('Checking root ${i.root}')\n\n\tfile_chan := chan string{cap: 1000}\n\terrors_chan := chan []ErrorInfo{cap: 1000}\n\n\tspawn fn [mut i, file_chan] () {\n\t\tif os.is_file(i.root) {\n\t\t\tfile_chan <- i.root\n\t\t\tfile_chan.close()\n\t\t\treturn\n\t\t}\n\n\t\tpath := i.root\n\t\tos.walk(path, fn [mut i, file_chan] (path string) {\n\t\t\tif i.need_check(path) {\n\t\t\t\tfile_chan <- path\n\t\t\t}\n\t\t})\n\n\t\tfile_chan.close()\n\t}()\n\n\tspawn i.spawn_checking_workers(errors_chan, file_chan)\n\n\tmut processed_files := 0\n\tmut errors := []ErrorInfo{cap: 100}\n\tfor {\n\t\terror := <-errors_chan or { break }\n\t\terrors << error\n\t\tprocessed_files++\n\t}\n\n\tmut per_file := map[string]bool{}\n\tfor error in errors {\n\t\tper_file[error.path] = true\n\t}\n\n\tprintln('Checking finished')\n\n\tfor error in errors[..50] {\n\t\tprintln(error)\n\t}\n\n\tprintln('Checking took ${time.since(now)}')\n\tprintln('\\nFound ${errors.len} errors in ${per_file.len} files')\n\tprintln('\\nParsed correctly ${(100 - (f64(per_file.len) / f64(processed_files) * 100))}% files out of ${processed_files}')\n}\n\npub fn (mut c Checker) check_file(path string) []ErrorInfo {\n\tcontent := os.read_file(path) or { return [] }\n\n\tmut p := parser.Parser.new()\n\tdefer { p.free() }\n\tres := p.parse_code(content)\n\n\troot := res.tree.root_node()\n\terrors := c.check_node(path, AstNode(root))\n\n\t// unsafe { res.tree.free() }\n\treturn errors\n}\n\npub fn (mut c Checker) check_node(path string, node AstNode) []ErrorInfo {\n\tmut errors := []ErrorInfo{}\n\tif node().type_name == .error {\n\t\terrors << c.create_error(path, node)\n\t}\n\n\tfor i := 0; i < node.child_count(); i++ {\n\t\tif child := node.child(u32(i)) {\n\t\t\terrors << c.check_node(path, child)\n\t\t}\n\t}\n\n\treturn errors\n}\n\npub fn (mut c Checker) create_error(path string, node AstNode) ErrorInfo {\n\treturn ErrorInfo{\n\t\tpath: path\n\t\tnode: node\n\t}\n}\n\npub fn (mut i Checker) spawn_checking_workers(errors_chan chan []ErrorInfo, file_chan chan string) {\n\tmut wg := sync.new_waitgroup()\n\tcpus := runtime.nr_cpus()\n\tworkers := math.max(cpus - 1, 1)\n\twg.add(workers)\n\tfor j := 0; j < workers; j++ {\n\t\tspawn fn [file_chan, mut wg, mut i, errors_chan] () {\n\t\t\tfor {\n\t\t\t\tfile := <-file_chan or { break }\n\t\t\t\terrors_chan <- i.check_file(file)\n\t\t\t}\n\n\t\t\twg.done()\n\t\t}()\n\t}\n\n\twg.wait()\n\terrors_chan.close()\n}\n"
  },
  {
    "path": "src/up.v",
    "content": "module main\n\nimport cli\nimport term\n\nfn up_cmd(cmd cli.Command) ! {\n\tdownload_install_vsh()!\n\n\tis_nightly := cmd.flags.get_bool('nightly') or { false }\n\tnightly_flag := if is_nightly { '--nightly' } else { '' }\n\n\tcommand := 'up ${nightly_flag}'\n\texit_code := call_install_vsh(command)!\n\n\tif exit_code != 0 {\n\t\terrorln('Failed to update ${term.bold('v-analyzer')}')\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "src/utils/text_utils.v",
    "content": "module utils\n\npub fn pascal_case_to_snake_case(s string) string {\n\tmut res := ''\n\tfor index, c in s {\n\t\tif c.ascii_str().is_upper() || c.is_digit() {\n\t\t\tif index > 0 {\n\t\t\t\tres += '_'\n\t\t\t}\n\t\t\tres += c.ascii_str().to_lower()\n\t\t} else {\n\t\t\tres += c.ascii_str()\n\t\t}\n\t}\n\treturn res\n}\n\npub fn snake_case_to_camel_case(s string) string {\n\tmut res := ''\n\tmut upper := false\n\tfor c in s {\n\t\tif c == `_` {\n\t\t\tupper = true\n\t\t} else {\n\t\t\tif upper {\n\t\t\t\tres += c.ascii_str().to_upper()\n\t\t\t\tupper = false\n\t\t\t} else {\n\t\t\t\tres += c.ascii_str()\n\t\t\t}\n\t\t}\n\t}\n\treturn res\n}\n\n// compute_offset returns a byte offset from the given position\npub fn compute_offset(src string, line int, col int) int {\n\tmut offset := 0\n\tmut src_line := 0\n\tmut src_col := 0\n\tsrc_len := src.len\n\tfor i := 0; i < src_len; i++ {\n\t\tbyt := src[i]\n\t\tis_lf := byt == `\\n`\n\t\tis_crlf := i + 1 < src_len && byt == `\\r` && src[i + 1] == `\\n`\n\t\tis_eol := is_lf || is_crlf\n\t\tif src_line == line && src_col == col {\n\t\t\treturn offset\n\t\t}\n\t\tif is_eol {\n\t\t\tif src_line == line && col > src_col {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\tsrc_line++\n\t\t\tsrc_col = 0\n\t\t\tif is_crlf {\n\t\t\t\toffset += 2\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\toffset++\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tsrc_col++\n\t\toffset++\n\t}\n\treturn offset\n}\n"
  },
  {
    "path": "src/utils/text_utils_test.v",
    "content": "module utils\n\nfn test_pascal_case_to_snake_case() {\n\tassert pascal_case_to_snake_case('CamelCase') == 'camel_case'\n\tassert pascal_case_to_snake_case('SomeValue') == 'some_value'\n\tassert pascal_case_to_snake_case('SomeValue') == 'some_value'\n\tassert pascal_case_to_snake_case('SomeValue1') == 'some_value_1'\n\tassert pascal_case_to_snake_case('Some') == 'some'\n}\n\nfn test_snake_case_to_camel_case() {\n\tassert snake_case_to_camel_case('snake_case') == 'snakeCase'\n\tassert snake_case_to_camel_case('some_value') == 'someValue'\n\tassert snake_case_to_camel_case('some_value_1') == 'someValue1'\n\tassert snake_case_to_camel_case('some') == 'some'\n}\n"
  },
  {
    "path": "src/utils.v",
    "content": "module main\n\nimport os\nimport term\nimport net.http\n\nconst download_dir = os.join_path(os.vtmp_dir(), 'v-analyzer')\nconst analyzer_install_script_download_path = 'https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh'\nconst analyzer_install_script_path = os.join_path(download_dir, 'install.vsh')\n\npub fn errorln(msg string) {\n\teprintln('${term.red('[ERROR]')} ${msg}')\n}\n\npub fn warnln(msg string) {\n\tprintln('${term.yellow('[WARN]')} ${msg}')\n}\n\npub fn infoln(msg string) {\n\tprintln('${term.blue('[INFO]')} ${msg}')\n}\n\npub fn successln(msg string) {\n\tprintln('${term.green('[SUCCESS]')} ${msg}')\n}\n\npub fn download_install_vsh() ! {\n\tif !os.exists(download_dir) {\n\t\tos.mkdir(download_dir) or { return error('Failed to create tmp dir: ${err}') }\n\t}\n\n\tmut file := os.create(analyzer_install_script_path) or {\n\t\treturn error('Error creating/opening file for script: ${err}')\n\t}\n\tdefer { file.close() }\n\n\treq := http.get(analyzer_install_script_download_path) or {\n\t\treturn error('Failed to download script: ${err}')\n\t}\n\n\tfile.write(req.body.bytes()) or { return error('Error writing to script file: ${err}') }\n}\n\npub fn call_install_vsh(cmd string) !int {\n\t$if windows {\n\t\t// On Windows we cannot use `os.Command` because it doesn't support Windows\n\t\tres := os.execute('v ${analyzer_install_script_path} ${cmd}')\n\t\tprintln(res.output)\n\t\treturn res.exit_code\n\t}\n\n\tmut command := os.Command{\n\t\tpath:            'v ${analyzer_install_script_path} ${cmd}'\n\t\tredirect_stdout: true\n\t}\n\n\tcommand.start()!\n\n\tfor !command.eof {\n\t\tprintln(command.read_line())\n\t}\n\n\tcommand.close()!\n\n\treturn command.exit_code\n}\n"
  },
  {
    "path": "tree_sitter_v/.gitattributes",
    "content": "src/tree_sitter/* linguist-generated\nsrc/grammar.json linguist-generated\nsrc/node-types.json linguist-generated\nsrc/parser.c linguist-generated\n"
  },
  {
    "path": "tree_sitter_v/.gitignore",
    "content": "# Avoid including irrelevant files\nnode_modules/\n*.log\nbuild/\npackage-lock.json\nPackage.swift\n\n# Ignore binary output folders\nbin/\n\n# Ignore common editor/system specific metadata\n.DS_Store\n.idea/\n.vscode/\n*.iml\n\ntarget/\nCargo.lock\nyarn.lock\n\nCargo.toml\n\nbindings/c/\nbindings/go/\nbindings/node/\nbindings/python/\nbindings/rust/\nbindings/swift/\nbinding.gyp\n\npyproject.toml\nsetup.py\n"
  },
  {
    "path": "tree_sitter_v/.prettierrc.js",
    "content": "module.exports = {\n\tprintWidth: 100,\n\tsingleQuote: true,\n\tuseTabs: true,\n};\n"
  },
  {
    "path": "tree_sitter_v/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Ned Palacios\nCopyright (c) 2023 V Open Source Community Association (VOSCA)\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": "tree_sitter_v/README.md",
    "content": "# tree-sitter-v\n\nV language grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter)\n\nThis grammar is heavily derived from the following language grammars:\n\n- [tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go)\n- [tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby/)\n- [tree-sitter-c](https://github.com/tree-sitter/tree-sitter-c/)\n\n## Limitations\n\n1. It does not support all deprecated/outdated syntaxes to avoid any ambiguities and to enforce the\n   one-way philosophy as much as possible.\n2. Assembly/SQL code in ASM/SQL block nodes are loosely checked and parsed immediately regardless of\n   the content.\n\n## Authors\n\nThis project initially started by\n[nedpals](https://github.com/nedpals)\nand after that, till July 2023, it was heavily modified by the\n[VOSCA](https://github.com/vlang-association).\n\nThe project is now developed by *all interested contributors*,\njust like [V itself](https://github.com/vlang/v).\n\n## License\n\nThis project is under the **MIT License**. See the\n[LICENSE](https://github.com/vlang/v-analyzer/blob/main/LICENSE)\nfile for the full license text.\n"
  },
  {
    "path": "tree_sitter_v/bindings/bindings.c.v",
    "content": "module bindings\n\n// This file contains the bindings for C API of tree-sitter.\n// They are indented to be used by wrapper functions in \"tree_sitter.v\".\n//\n// See \"core/lib/include/tree_sitter/api.h\" for function references.\n\n// We directly build \"lib.c\" rather using the static library.\n#flag -I @VMODROOT/tree_sitter_v/bindings/core/lib/include\n#flag -I @VMODROOT/tree_sitter_v/bindings/core/lib/src\n#flag @VMODROOT/tree_sitter_v/bindings/core/lib/src/lib.c\n#include \"tree_sitter/api.h\"\n\n#flag -I @VMODROOT/tree_sitter_v/bindings\n#flag -I @VMODROOT/tree_sitter_v/src\n#flag @VMODROOT/tree_sitter_v/src/parser.c\n#include \"bindings.h\"\n\npub type TSDecodeFunction = fn (string, u32, &int) u32\n\npub enum TSVInputEncoding {\n\tutf8\n\tutf16le\n\tutf16be\n\tcustom\n}\n\npub type C.TSInputEncoding = TSVInputEncoding\n\n@[typedef]\npub struct C.TSInput {\nmut:\n\tpayload  voidptr\n\tread     fn (payload voidptr, byte_index u32, position C.TSPoint, bytes_read &u32) &char\n\tencoding C.TSInputEncoding\n\tdecode   TSDecodeFunction\n}\n\n@[typedef]\npub struct C.TSLanguage {}\n\n@[typedef]\npub struct C.TSParser {}\n\nfn C.tree_sitter_v() &C.TSLanguage\nfn C.ts_parser_new() &C.TSParser\nfn C.ts_parser_set_language(parser &C.TSParser, language &C.TSLanguage) bool\nfn C.ts_parser_parse_string(parser &C.TSParser, const_old_tree &C.TSTree, str &char, len u32) &C.TSTree\nfn C.ts_parser_parse(parser &C.TSParser, const_old_tree &C.TSTree, input C.TSInput) &C.TSTree\nfn C.ts_parser_delete(tree &C.TSParser)\nfn C.ts_parser_reset(parser &C.TSParser)\n\n@[inline]\nfn new_ts_parser() &C.TSParser {\n\treturn C.ts_parser_new()\n}\n\n@[inline]\nfn (mut p C.TSParser) parse(old_tree &TSTree, input C.TSInput) &TSTree {\n\treturn &TSTree(C.ts_parser_parse(p, voidptr(old_tree), input))\n}\n\n@[inline]\nfn (mut p C.TSParser) reset() {\n\tC.ts_parser_reset(p)\n}\n\n@[inline]\nfn (mut p C.TSParser) set_language(language &C.TSLanguage) bool {\n\treturn C.ts_parser_set_language(p, language)\n}\n\n@[inline]\nfn (mut p C.TSParser) parse_string(content string) &TSTree {\n\treturn p.parse_string_with_old_tree(content, &TSTree(unsafe { nil }))\n}\n\n@[inline]\nfn (mut p C.TSParser) parse_string_with_old_tree(content string, old_tree &TSTree) &TSTree {\n\treturn p.parse_string_with_old_tree_and_len(content, old_tree, u32(content.len))\n}\n\n@[inline]\nfn (mut p C.TSParser) parse_string_with_old_tree_and_len(content string, old_tree &TSTree, len u32) &TSTree {\n\treturn &TSTree(C.ts_parser_parse_string(p, voidptr(old_tree), &char(content.str), len))\n}\n\n@[inline]\nfn (mut p C.TSParser) parse_bytes(content []u8) &TSTree {\n\treturn p.parse_bytes_with_old_tree(content, &TSTree(unsafe { nil }))\n}\n\nfn byte_array_input_read(pl voidptr, byte_index u32, position C.TSPoint, bytes_read &u32) &char {\n\tpayload := *(&[]u8(pl))\n\tif byte_index >= u32(payload.len) {\n\t\tunsafe {\n\t\t\t*bytes_read = 0\n\t\t}\n\t\treturn c''\n\t} else {\n\t\tunsafe {\n\t\t\t*bytes_read = u32(payload.len) - byte_index\n\t\t}\n\t\treturn unsafe { &char(payload.data) + byte_index }\n\t}\n}\n\nfn (mut p C.TSParser) parse_bytes_with_old_tree(content []u8, old_tree &TSTree) &TSTree {\n\treturn p.parse(old_tree,\n\t\tpayload:  &content\n\t\tread:     byte_array_input_read\n\t\tencoding: TSVInputEncoding.utf8\n\t)\n}\n\n@[inline; unsafe]\nfn (p &C.TSParser) delete() {\n\tunsafe {\n\t\tC.ts_parser_delete(p)\n\t}\n}\n\n@[typedef]\npub struct C.TSLanguage {}\n\npub struct C.TSTree {\n\tincluded_range_count u32\n}\n\n@[export: 'TSTree']\npub struct TSTree {\n\tincluded_range_count u32\n}\n\nfn C.ts_tree_copy(tree &C.TSTree) &C.TSTree\nfn C.ts_tree_root_node(tree &C.TSTree) C.TSNode\nfn C.ts_tree_delete(tree &C.TSTree)\nfn C.ts_tree_edit(tree &C.TSTree, edit &C.TSInputEdit)\nfn C.ts_tree_get_changed_ranges(old_tree &C.TSTree, new_tree &C.TSTree, count &u32) &C.TSRange\n\n@[inline]\nfn (tree &TSTree) copy() &TSTree {\n\treturn &TSTree(C.ts_tree_copy(voidptr(tree)))\n}\n\n@[inline]\nfn (tree &TSTree) root_node() C.TSNode {\n\treturn C.ts_tree_root_node(&C.TSTree(tree))\n}\n\n@[inline]\nfn (tree &TSTree) edit(input_edit &C.TSInputEdit) {\n\tC.ts_tree_edit(&C.TSTree(tree), input_edit)\n}\n\nfn (tree &TSTree) get_changed_ranges(new_tree &TSTree) []C.TSRange {\n\tmut len := u32(0)\n\tbuf := C.ts_tree_get_changed_ranges(&C.TSTree(tree), &C.TSTree(new_tree), &len)\n\telement_size := int(sizeof(C.TSRange))\n\n\treturn unsafe {\n\t\tarray{\n\t\t\telement_size: element_size\n\t\t\tlen:          int(len)\n\t\t\tcap:          int(len)\n\t\t\tdata:         buf\n\t\t}\n\t}\n}\n\n@[unsafe]\nfn (tree &TSTree) free() {\n\tunsafe {\n\t\tC.ts_tree_delete(&C.TSTree(tree))\n\t}\n}\n\n@[typedef]\npub struct C.TSNode {\n\tcontext [4]u32\n\tid      voidptr\n\ttree    &TSTree\n}\n\nfn C.ts_node_string(node C.TSNode) &char\nfn C.ts_node_type(node C.TSNode) &char\nfn C.ts_node_is_null(node C.TSNode) bool\nfn C.ts_node_is_named(node C.TSNode) bool\nfn C.ts_node_is_missing(node C.TSNode) bool\nfn C.ts_node_is_extra(node C.TSNode) bool\nfn C.ts_node_has_changes(node C.TSNode) bool\nfn C.ts_node_has_error(node C.TSNode) bool\n\nfn C.ts_node_start_point(node C.TSNode) C.TSPoint\nfn C.ts_node_end_point(node C.TSNode) C.TSPoint\nfn C.ts_node_start_byte(node C.TSNode) u32\nfn C.ts_node_end_byte(node C.TSNode) u32\n\nfn C.ts_node_parent(node C.TSNode) C.TSNode\nfn C.ts_node_child(node C.TSNode, index u32) C.TSNode\nfn C.ts_node_child_count(node C.TSNode) u32\nfn C.ts_node_named_child(node C.TSNode, index u32) C.TSNode\nfn C.ts_node_named_child_count(node C.TSNode) u32\nfn C.ts_node_child_by_field_name(node C.TSNode, field_name &char, field_name_length u32) C.TSNode\n\nfn C.ts_node_next_sibling(node C.TSNode) C.TSNode\nfn C.ts_node_prev_sibling(node C.TSNode) C.TSNode\nfn C.ts_node_next_named_sibling(node C.TSNode) C.TSNode\nfn C.ts_node_prev_named_sibling(node C.TSNode) C.TSNode\n\nfn C.ts_node_first_child_for_byte(node C.TSNode, offset u32) C.TSNode\nfn C.ts_node_first_named_child_for_byte(node C.TSNode, offset u32) C.TSNode\n\nfn C.ts_node_descendant_for_byte_range(node C.TSNode, start_offset u32, end_offset u32) C.TSNode\nfn C.ts_node_descendant_for_point_range(node C.TSNode, start_point C.TSPoint, end_point C.TSPoint) C.TSNode\nfn C.ts_node_named_descendant_for_byte_range(node C.TSNode, start_offset u32, end_offset u32) C.TSNode\nfn C.ts_node_named_descendant_for_point_range(node C.TSNode, start_point C.TSPoint, end_point C.TSPoint) C.TSNode\n\nfn C.ts_node_eq(node C.TSNode, another_node C.TSNode) bool\n\npub fn (node C.TSNode) text(text string) string {\n\tstart_index := node.start_byte()\n\tend_index := node.end_byte()\n\tif start_index >= end_index || start_index >= u32(text.len) || end_index > u32(text.len) {\n\t\treturn ''\n\t}\n\treturn text.substr(int(start_index), int(end_index))\n}\n\n@[inline]\nfn (node C.TSNode) sexpr_str() string {\n\tif node.is_null() {\n\t\treturn '<null node>'\n\t}\n\n\tsexpr := C.ts_node_string(node)\n\treturn unsafe { sexpr.vstring() }\n}\n\n@[inline]\npub fn (node C.TSNode) text_length() u32 {\n\tstart := node.start_byte()\n\tend := node.end_byte()\n\treturn end - start\n}\n\n@[inline]\npub fn (node C.TSNode) start_point() C.TSPoint {\n\tif node.is_null() {\n\t\treturn C.TSPoint{0, 0}\n\t}\n\n\treturn C.ts_node_start_point(node)\n}\n\nfn (node C.TSNode) end_point() C.TSPoint {\n\tif node.is_null() {\n\t\treturn C.TSPoint{0, 0}\n\t}\n\n\treturn C.ts_node_end_point(node)\n}\n\nfn (node C.TSNode) start_byte() u32 {\n\tif node.is_null() {\n\t\treturn 0\n\t}\n\n\treturn C.ts_node_start_byte(node)\n}\n\nfn (node C.TSNode) end_byte() u32 {\n\tif node.is_null() {\n\t\treturn 0\n\t}\n\n\treturn C.ts_node_end_byte(node)\n}\n\n@[inline]\nfn (node C.TSNode) range() C.TSRange {\n\treturn C.TSRange{\n\t\tstart_point: node.start_point()\n\t\tend_point:   node.end_point()\n\t\tstart_byte:  node.start_byte()\n\t\tend_byte:    node.end_byte()\n\t}\n}\n\npub fn (node C.TSNode) type_name() string {\n\tif node.is_null() {\n\t\treturn '<null node>'\n\t}\n\tc := &char(C.ts_node_type(node))\n\treturn unsafe { c.vstring() }\n}\n\n@[inline]\nfn (node C.TSNode) is_null() bool {\n\treturn C.ts_node_is_null(node)\n}\n\n@[inline]\nfn (node C.TSNode) is_named() bool {\n\treturn C.ts_node_is_named(node)\n}\n\n@[inline]\nfn (node C.TSNode) is_missing() bool {\n\treturn C.ts_node_is_missing(node)\n}\n\n@[inline]\nfn (node C.TSNode) is_extra() bool {\n\treturn C.ts_node_is_extra(node)\n}\n\n@[inline]\nfn (node C.TSNode) has_changes() bool {\n\treturn C.ts_node_has_changes(node)\n}\n\nfn (node C.TSNode) is_error() bool {\n\tif node.is_null() {\n\t\treturn true\n\t}\n\treturn C.ts_node_has_error(node)\n}\n\npub fn (node C.TSNode) parent_nth(depth int) ?TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tmut res := node\n\tfor _ in 0 .. depth {\n\t\tres = res.parent()?\n\t}\n\tif res.is_null() {\n\t\treturn none\n\t}\n\treturn res\n}\n\npub fn (node C.TSNode) parent() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tparent := C.ts_node_parent(node)\n\tif parent.is_null() {\n\t\treturn none\n\t}\n\treturn parent\n}\n\npub fn (node C.TSNode) first_child() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tcount_child := node.child_count()\n\tif count_child == 0 {\n\t\treturn none\n\t}\n\tchild := C.ts_node_child(node, 0)\n\tif child.is_null() {\n\t\treturn none\n\t}\n\treturn child\n}\n\npub fn (node C.TSNode) last_child() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tcount_child := node.child_count()\n\tif count_child == 0 {\n\t\treturn none\n\t}\n\tchild := C.ts_node_child(node, count_child - 1)\n\tif child.is_null() {\n\t\treturn none\n\t}\n\treturn child\n}\n\nfn (node C.TSNode) child(index u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tchild := C.ts_node_child(node, index)\n\tif child.is_null() {\n\t\treturn none\n\t}\n\treturn child\n}\n\n@[inline]\nfn (node C.TSNode) child_count() u32 {\n\treturn C.ts_node_child_count(node)\n}\n\nfn (node C.TSNode) named_child(pos u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tchild := C.ts_node_named_child(node, pos)\n\tif child.is_null() {\n\t\treturn none\n\t}\n\treturn child\n}\n\nfn (node C.TSNode) named_child_count() u32 {\n\tif node.is_null() {\n\t\treturn 0\n\t}\n\treturn C.ts_node_named_child_count(node)\n}\n\npub fn (node C.TSNode) child_by_field_name(name string) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tchild := C.ts_node_child_by_field_name(node, &char(name.str), u32(name.len))\n\tif child.is_null() {\n\t\treturn none\n\t}\n\n\treturn child\n}\n\nfn (node C.TSNode) next_sibling() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tsibling := C.ts_node_next_sibling(node)\n\tif sibling.is_null() {\n\t\treturn none\n\t}\n\treturn sibling\n}\n\nfn (node C.TSNode) prev_sibling() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tsibling := C.ts_node_prev_sibling(node)\n\tif sibling.is_null() {\n\t\treturn none\n\t}\n\treturn sibling\n}\n\nfn (node C.TSNode) next_named_sibling() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tsibling := C.ts_node_next_named_sibling(node)\n\tif sibling.is_null() {\n\t\treturn none\n\t}\n\treturn sibling\n}\n\nfn (node C.TSNode) prev_named_sibling() ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tsibling := C.ts_node_prev_named_sibling(node)\n\tif sibling.is_null() {\n\t\treturn none\n\t}\n\treturn sibling\n}\n\nfn (node C.TSNode) first_child_for_byte(offset u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_first_child_for_byte(node, offset)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn (node C.TSNode) first_named_child_for_byte(offset u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_first_named_child_for_byte(node, offset)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn (node C.TSNode) descendant_for_byte_range(start_range u32, end_range u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_descendant_for_byte_range(node, start_range, end_range)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn (node C.TSNode) descendant_for_point_range(start_point C.TSPoint, end_point C.TSPoint) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_descendant_for_point_range(node, start_point, end_point)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn (node C.TSNode) named_descendant_for_byte_range(start_range u32, end_range u32) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_named_descendant_for_byte_range(node, start_range, end_range)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn (node C.TSNode) named_descendant_for_point_range(start_point C.TSPoint, end_point C.TSPoint) ?C.TSNode {\n\tif node.is_null() {\n\t\treturn none\n\t}\n\tgot_node := C.ts_node_named_descendant_for_point_range(node, start_point, end_point)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\nfn C.ts_tree_cursor_new(node C.TSNode) C.TSTreeCursor\n\npub type TSTreeCursor = C.TSTreeCursor\n\n@[inline]\npub fn (node C.TSNode) tree_cursor() TSTreeCursor {\n\treturn C.ts_tree_cursor_new(node)\n}\n\n@[typedef]\npub struct C.TSTreeCursor {\n\ttree    voidptr\n\tid      voidptr\n\tcontext [3]u32\n}\n\nfn C.ts_tree_cursor_delete(cursor &C.TSTreeCursor)\nfn C.ts_tree_cursor_reset(cursor &C.TSTreeCursor, node C.TSNode)\nfn C.ts_tree_cursor_current_node(cursor &C.TSTreeCursor) C.TSNode\nfn C.ts_tree_cursor_current_field_name(cursor &C.TSTreeCursor) &char\nfn C.ts_tree_cursor_goto_parent(cursor &C.TSTreeCursor) bool\nfn C.ts_tree_cursor_goto_next_sibling(cursor &C.TSTreeCursor) bool\nfn C.ts_tree_cursor_goto_first_child(cursor &C.TSTreeCursor) bool\nfn C.ts_tree_cursor_first_child_for_byte(cursor &C.TSTreeCursor, idx u32) i64\nfn C.ts_tree_cursor_copy(cursor &C.TSTreeCursor) C.TSTreeCursor\n\n@[inline; unsafe]\npub fn (cursor &C.TSTreeCursor) delete() {\n\tC.ts_tree_cursor_delete(cursor)\n}\n\n@[inline]\nfn (mut cursor C.TSTreeCursor) reset(node C.TSNode) {\n\tC.ts_tree_cursor_reset(cursor, node)\n}\n\npub type TSNode = C.TSNode\n\n@[inline]\npub fn (cursor &C.TSTreeCursor) current_node() ?TSNode {\n\tgot_node := C.ts_tree_cursor_current_node(cursor)\n\tif got_node.is_null() {\n\t\treturn none\n\t}\n\treturn got_node\n}\n\n@[inline]\npub fn (cursor &C.TSTreeCursor) current_field_name() string {\n\tc := &char(C.ts_tree_cursor_current_field_name(cursor))\n\treturn unsafe { c.vstring() }\n}\n\n@[inline]\npub fn (mut cursor C.TSTreeCursor) to_parent() bool {\n\treturn C.ts_tree_cursor_goto_parent(cursor)\n}\n\n@[inline]\npub fn (mut cursor C.TSTreeCursor) next() bool {\n\treturn C.ts_tree_cursor_goto_next_sibling(cursor)\n}\n\n@[inline]\npub fn (mut cursor C.TSTreeCursor) to_first_child() bool {\n\treturn C.ts_tree_cursor_goto_first_child(cursor)\n}\n\n@[typedef]\npub struct C.TSInputEdit {\n\tstart_byte    u32\n\told_end_byte  u32\n\tnew_end_byte  u32\n\tstart_point   C.TSPoint\n\told_end_point C.TSPoint\n\tnew_end_point C.TSPoint\n}\n\n@[typedef]\npub struct C.TSPoint {\npub:\n\trow    u32\n\tcolumn u32\n}\n\nfn (left_point C.TSPoint) eq(right_point C.TSPoint) bool {\n\treturn left_point.row == right_point.row && left_point.column == right_point.column\n}\n\n@[typedef]\npub struct C.TSRange {\npub:\n\tstart_point C.TSPoint\n\tend_point   C.TSPoint\n\tstart_byte  u32\n\tend_byte    u32\n}\n\nfn (left_range C.TSRange) eq(right_range C.TSRange) bool {\n\treturn left_range.start_point.eq(right_range.start_point)\n\t\t&& left_range.end_point.eq(right_range.end_point)\n\t\t&& left_range.start_byte == right_range.start_byte\n\t\t&& left_range.end_byte == right_range.end_byte\n}\n"
  },
  {
    "path": "tree_sitter_v/bindings/bindings.h",
    "content": "#ifndef TREE_SITTER_V_H_\n#define TREE_SITTER_V_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nconst TSLanguage *tree_sitter_v(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // TREE_SITTER_V_H_\n"
  },
  {
    "path": "tree_sitter_v/bindings/bindings.v",
    "content": "module bindings\n\npub type TSParser = C.TSParser\npub type TSLanguage = C.TSLanguage\n\npub const language = unsafe { &TSLanguage(C.tree_sitter_v()) }\n\npub struct Parser[T] {\nmut:\n\traw_parser   &TSParser = unsafe { nil }          @[required]\n\ttype_factory NodeTypeFactory[T] @[required]\n}\n\npub fn new_parser[T](type_factory NodeTypeFactory[T]) &Parser[T] {\n\tmut parser := new_ts_parser()\n\treturn &Parser[T]{\n\t\traw_parser:   parser\n\t\ttype_factory: type_factory\n\t}\n}\n\n@[inline]\npub fn (mut p Parser[T]) set_language(language &TSLanguage) {\n\tp.raw_parser.set_language(language)\n}\n\n@[inline]\npub fn (mut p Parser[T]) reset() {\n\tp.raw_parser.reset()\n}\n\n@[inline]\npub fn (p &Parser[T]) free() {\n\tunsafe {\n\t\tp.raw_parser.delete()\n\t}\n}\n\n@[params]\npub struct ParseConfig {\npub:\n\tsource string @[required]\n\ttree   &TSTree = &TSTree(unsafe { nil })\n}\n\npub fn (mut p Parser[T]) parse_string(cfg ParseConfig) &Tree[T] {\n\ttree := p.raw_parser.parse_string_with_old_tree(cfg.source, cfg.tree)\n\treturn &Tree[T]{\n\t\traw_tree:     tree\n\t\ttype_factory: p.type_factory\n\t}\n}\n\npub interface NodeTypeFactory[T] {\n\tget_type(type_name string) T\n}\n\npub struct Tree[T] {\n\ttype_factory NodeTypeFactory[T] @[required]\npub:\n\traw_tree &TSTree = unsafe { nil } @[required]\n}\n\n@[unsafe]\npub fn (tree &Tree[T]) free() {\n\tunsafe { tree.raw_tree.free() }\n}\n\npub fn (tree Tree[T]) root_node() Node[T] {\n\treturn new_tsnode[T](tree.type_factory, tree.raw_tree.root_node())\n}\n\npub fn new_tsnode[T](factory NodeTypeFactory[T], node TSNode) Node[T] {\n\treturn Node[T]{\n\t\traw_node:     node\n\t\ttype_factory: factory\n\t\ttype_name:    factory.get_type(node.type_name())\n\t}\n}\n\npub struct Node[T] {\n\ttype_factory NodeTypeFactory[T] @[required]\npub:\n\traw_node  TSNode @[required]\n\ttype_name T      @[required]\n}\n\n@[inline]\npub fn (node Node[T]) text(text string) string {\n\treturn node.raw_node.text(text)\n}\n\n@[inline]\npub fn (node Node[T]) text_matches(all_text string, text_to_find string) bool {\n\ttext_len := u32(text_to_find.len)\n\tnode_len := node.text_length()\n\n\t// if the text we are looking for does not match in length,\n\t// then the text cannot exactly match\n\tif text_len != node_len {\n\t\treturn false\n\t}\n\n\treturn node.text(all_text) == text_to_find\n}\n\n@[inline]\npub fn (node Node[T]) first_char(text string) u8 {\n\tstart_index := node.start_byte()\n\tif start_index >= u32(text.len) {\n\t\treturn 0\n\t}\n\treturn text[start_index]\n}\n\n@[inline]\npub fn (node Node[T]) text_length() u32 {\n\tstart := node.raw_node.start_byte()\n\tend := node.raw_node.end_byte()\n\treturn end - start\n}\n\n@[inline]\npub fn (node Node[T]) str() string {\n\treturn node.raw_node.sexpr_str()\n}\n\n@[inline]\npub fn (node Node[T]) start_point() TSPoint {\n\treturn node.raw_node.start_point()\n}\n\n@[inline]\npub fn (node Node[T]) end_point() TSPoint {\n\treturn node.raw_node.end_point()\n}\n\n@[inline]\npub fn (node Node[T]) start_byte() u32 {\n\treturn node.raw_node.start_byte()\n}\n\n@[inline]\npub fn (node Node[T]) end_byte() u32 {\n\treturn node.raw_node.end_byte()\n}\n\n@[inline]\npub fn (node Node[T]) range() TSRange {\n\treturn node.raw_node.range()\n}\n\n@[inline]\npub fn (node Node[T]) is_null() bool {\n\treturn node.raw_node.is_null()\n}\n\n@[inline]\npub fn (node Node[T]) is_leaf() bool {\n\treturn node.child_count() == 0\n}\n\n@[inline]\npub fn (node Node[T]) is_named() bool {\n\treturn node.raw_node.is_named()\n}\n\n@[inline]\npub fn (node Node[T]) is_missing() bool {\n\treturn node.raw_node.is_missing()\n}\n\n@[inline]\npub fn (node Node[T]) is_extra() bool {\n\treturn node.raw_node.is_extra()\n}\n\n@[inline]\npub fn (node Node[T]) has_changes() bool {\n\treturn node.raw_node.has_changes()\n}\n\n@[inline]\npub fn (node Node[T]) is_error() bool {\n\treturn node.raw_node.is_error()\n}\n\npub fn (node Node[T]) parent() ?Node[T] {\n\tparent := node.raw_node.parent()?\n\treturn new_tsnode[T](node.type_factory, parent)\n}\n\npub fn (node Node[T]) parent_nth(depth int) ?Node[T] {\n\tmut res := node.raw_node\n\tfor _ in 0 .. depth {\n\t\tres = res.parent()?\n\t}\n\treturn new_tsnode[T](node.type_factory, res)\n}\n\npub fn (node Node[T]) is_parent_of(other Node[T]) bool {\n\tmut parent := other.parent() or { return false }\n\n\tfor {\n\t\tif parent.equal(node) {\n\t\t\treturn true\n\t\t}\n\t\tparent = parent.parent() or { break }\n\t}\n\n\treturn false\n}\n\npub fn (node Node[T]) child(pos u32) ?Node[T] {\n\tchild := node.raw_node.child(pos)?\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\n@[inline]\npub fn (node Node[T]) child_count() u32 {\n\treturn node.raw_node.child_count()\n}\n\npub fn (node Node[T]) named_child(pos u32) ?Node[T] {\n\tchild := node.raw_node.named_child(pos)?\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\n@[inline]\npub fn (node Node[T]) named_child_count() u32 {\n\treturn node.raw_node.named_child_count()\n}\n\npub fn (node Node[T]) child_by_field_name(name string) ?Node[T] {\n\tchild := node.raw_node.child_by_field_name(name)?\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\npub fn (node Node[T]) first_child() ?Node[T] {\n\tcount_child := node.child_count()\n\tif count_child == 0 {\n\t\treturn none\n\t}\n\tchild := node.raw_node.child(0) or { return none }\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\npub fn (node Node[T]) last_child() ?Node[T] {\n\tcount_child := node.child_count()\n\tif count_child == 0 {\n\t\treturn none\n\t}\n\tchild := node.raw_node.child(count_child - 1) or { return none }\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\npub fn (node Node[T]) next_sibling() ?Node[T] {\n\tsibling := node.raw_node.next_sibling() or { return none }\n\treturn new_tsnode[T](node.type_factory, sibling)\n}\n\npub fn (node Node[T]) prev_sibling() ?Node[T] {\n\tsibling := node.raw_node.prev_sibling() or { return none }\n\treturn new_tsnode[T](node.type_factory, sibling)\n}\n\npub fn (node Node[T]) next_named_sibling() ?Node[T] {\n\tsibling := node.raw_node.next_named_sibling() or { return none }\n\treturn new_tsnode[T](node.type_factory, sibling)\n}\n\npub fn (node Node[T]) prev_named_sibling() ?Node[T] {\n\tsibling := node.raw_node.prev_named_sibling() or { return none }\n\treturn new_tsnode[T](node.type_factory, sibling)\n}\n\npub fn (node Node[T]) first_child_for_byte(offset u32) ?Node[T] {\n\tchild := node.raw_node.first_child_for_byte(offset) or { return none }\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\npub fn (node Node[T]) first_named_child_for_byte(offset u32) ?Node[T] {\n\tchild := node.raw_node.first_named_child_for_byte(offset) or { return none }\n\treturn new_tsnode[T](node.type_factory, child)\n}\n\npub fn (node Node[T]) descendant_for_byte_range(start_range u32, end_range u32) ?Node[T] {\n\tdesc := node.raw_node.descendant_for_byte_range(start_range, end_range) or { return none }\n\treturn new_tsnode[T](node.type_factory, desc)\n}\n\npub fn (node Node[T]) descendant_for_point_range(start_point TSPoint, end_point TSPoint) ?Node[T] {\n\tdesc := node.raw_node.descendant_for_point_range(start_point, end_point) or { return none }\n\treturn new_tsnode[T](node.type_factory, desc)\n}\n\npub fn (node Node[T]) named_descendant_for_byte_range(start_range u32, end_range u32) ?Node[T] {\n\tdesc := node.raw_node.named_descendant_for_byte_range(start_range, end_range) or { return none }\n\treturn new_tsnode[T](node.type_factory, desc)\n}\n\npub fn (node Node[T]) named_descendant_for_point_range(start_point TSPoint, end_point TSPoint) ?Node[T] {\n\tdesc := node.raw_node.named_descendant_for_point_range(start_point, end_point) or {\n\t\treturn none\n\t}\n\treturn new_tsnode[T](node.type_factory, desc)\n}\n\npub fn (node Node[T]) first_node_by_type(type_name T) ?Node[T] {\n\tmut named_child := node.named_child(0) or { return none }\n\tlen := node.child_count()\n\tfor i := 0; i < int(len); i++ {\n\t\tif named_child.type_name == type_name {\n\t\t\treturn named_child\n\t\t}\n\t\tnamed_child = named_child.next_sibling() or { continue }\n\t}\n\treturn none\n}\n\npub fn (node Node[T]) last_node_by_type(type_name T) ?Node[T] {\n\tlen := node.child_count()\n\tmut named_child := node.named_child(len - 1) or { return none }\n\tfor i := int(len - 1); i >= 0; i-- {\n\t\tif named_child.type_name == type_name {\n\t\t\treturn named_child\n\t\t}\n\t\tnamed_child = named_child.prev_sibling() or { continue }\n\t}\n\treturn none\n}\n\n@[inline]\npub fn (node Node[T]) == (other_node Node[T]) bool {\n\treturn C.ts_node_eq(node.raw_node, other_node.raw_node)\n}\n\n@[inline]\npub fn (node Node[T]) equal(other_node Node[T]) bool {\n\treturn C.ts_node_eq(node.raw_node, other_node.raw_node)\n}\n\n@[inline]\npub fn (node Node[T]) tree_cursor() TreeCursor[T] {\n\treturn TreeCursor[T]{\n\t\ttype_factory: node.type_factory\n\t\traw_cursor:   node.raw_node.tree_cursor()\n\t}\n}\n\npub struct TreeCursor[T] {\n\ttype_factory NodeTypeFactory[T] @[required]\npub mut:\n\traw_cursor C.TSTreeCursor @[required]\n}\n\n@[inline]\npub fn (mut cursor TreeCursor[T]) reset(node Node[T]) {\n\tcursor.raw_cursor.reset(node.raw_node)\n}\n\n@[inline]\npub fn (cursor TreeCursor[T]) current_node() ?Node[T] {\n\tgot_node := cursor.raw_cursor.current_node()?\n\treturn new_tsnode[T](cursor.type_factory, got_node)\n}\n\n@[inline]\npub fn (cursor TreeCursor[T]) current_field_name() string {\n\treturn cursor.raw_cursor.current_field_name()\n}\n\n@[inline]\npub fn (mut cursor TreeCursor[T]) to_parent() bool {\n\treturn cursor.raw_cursor.to_parent()\n}\n\n@[inline]\npub fn (mut cursor TreeCursor[T]) next() bool {\n\treturn cursor.raw_cursor.next()\n}\n\n@[inline]\npub fn (mut cursor TreeCursor[T]) to_first_child() bool {\n\treturn cursor.raw_cursor.to_first_child()\n}\n\npub type TSRange = C.TSRange\n\npub fn (r TSRange) str() string {\n\treturn '\n{\n    start: ${TSPoint(r.start_point)}\n    end: ${TSPoint(r.end_point)}\n    start_byte: ${r.start_byte}\n    end_byte: ${r.end_byte}\n}\n'.trim_indent()\n}\n\npub type TSPoint = C.TSPoint\n\npub fn (p TSPoint) str() string {\n\treturn '(${p.row}, ${p.column})'\n}\n"
  },
  {
    "path": "tree_sitter_v/bindings/generate_types.vsh",
    "content": "import json\nimport strings\nimport os\n\n// This is a script file which creates static type declarations\n// for tree-sitter-v's node types by using the information found\n// in 'node-types.json' and turn it into a pseudo-sum type using enums\n// and create a `NodeTypeFactory` implementation that will convert type names\n// into respective `NodeType` enum.\n// Anonymous nodes are automatically identified as `NodeType.unknown`.\n//\n// See: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types\n\nconst to_be_escaped = ['none', 'true', 'false', 'map', 'type', 'nil']\n\nfn escape_name(name string) string {\n\tif name in to_be_escaped {\n\t\treturn name + '_'\n\t}\n\treturn name\n}\n\nfn write_enum_member(mut wr strings.Builder, type_name string, member_name string) {\n\twr.write_string('${type_name}.${escape_name(member_name)}')\n}\n\nfn write_enum_array(mut wr strings.Builder, enum_type_name string, list []string) {\n\twr.writeln('[')\n\tfor i, name in list {\n\t\twr.write_string('   ')\n\n\t\t// write fully qualified name for enum member only for the first member\n\t\ttype_name := if i == 0 { enum_type_name } else { '' }\n\t\twrite_enum_member(mut wr, type_name, name)\n\n\t\tif i < list.len - 1 {\n\t\t\twr.write_u8(`,`)\n\t\t}\n\t\twr.write_u8(`\\n`)\n\t}\n\twr.write_u8(`]`)\n}\n\nfn write_const_enum_array(mut wr strings.Builder, var_name string, enum_type_name string, list []string) {\n\twr.write_string('\\nconst ${var_name} = ')\n\twrite_enum_array(mut wr, enum_type_name, list)\n\twr.write_u8(`\\n`)\n}\n\nstruct TSNodeType {\n\tname     string @[json: 'type']\n\tnamed    bool\n\tsubtypes []TSNodeType\n}\n\nfn (typ TSNodeType) is_anon() bool {\n\treturn !typ.named || typ.name.len == 0 || typ.name[0] == `_`\n}\n\ncur_dir := dir(@FILE)\nnode_types_json := read_file(join_path(@VMODROOT, 'tree_sitter_v', 'src', 'node-types.json'))!\nnode_types := json.decode([]TSNodeType, node_types_json)!\nnode_type_enum_name := 'NodeType'\nsuper_type_enum_name := 'SuperType'\n\nfile_path := join_path(cur_dir, 'node_types.v')\nmut file := open_file(file_path, 'w+')!\nmut sb := strings.new_builder(1024 * 1024)\nmut supertype_node_groups := map[string][]string{}\n\nsb.writeln('// This is an AUTO-GENERATED file. DO NOT EDIT this file directly! See `generate_types.vsh`')\n\nsb.writeln('module bindings')\nsb.writeln('\\n')\nsb.writeln('import arrays { merge }')\n\n// write supertypes\nsb.writeln('pub enum ${super_type_enum_name} {')\nsb.writeln('   unknown')\nfor node_type in node_types {\n\tif !node_type.named || node_type.name.len == 0 || node_type.name[0] != `_`\n\t\t|| node_type.subtypes.len == 0 {\n\t\tcontinue\n\t}\n\tsb.writeln('   ${escape_name(node_type.name[1..])}')\n\tsupertype_node_groups[node_type.name] = node_type.subtypes.map(it.name)\n}\nsb.writeln('}\\n')\n\nsb.writeln('pub enum ${node_type_enum_name} {')\nsb.writeln('   unknown')\nsb.writeln('   error')\n\nmut declaration_node_types := []string{cap: 100}\nmut identifier_node_types := []string{cap: 100}\nmut literal_node_types := []string{cap: 100}\n\n// write node types as enum members\nfor node_type in node_types {\n\tif node_type.is_anon() {\n\t\tcontinue\n\t}\n\n\tif node_type.name.ends_with('_declaration') {\n\t\tdeclaration_node_types << node_type.name\n\t} else if node_type.name == 'identifier' || node_type.name.ends_with('_identifier') {\n\t\tidentifier_node_types << node_type.name\n\t} else if node_type.name.ends_with('_literal') {\n\t\tliteral_node_types << node_type.name\n\t}\n\n\tsb.writeln('   ${escape_name(node_type.name)}')\n}\nsb.writeln('}')\n\nfor supertype_name, supertype_node_types in supertype_node_groups {\n\tsb.write_string('\\n')\n\tsb.write_string('const supertype_${supertype_name}_nodes = ')\n\tsuper_type_members := supertype_node_types.filter(it.starts_with('_'))\n\tfor type_member in super_type_members {\n\t\tsb.write_string('merge(supertype_${type_member}_nodes, ')\n\t}\n\twrite_enum_array(mut sb, node_type_enum_name, supertype_node_types.filter(!it.starts_with('_')))\n\tsb.writeln(')'.repeat(super_type_members.len))\n}\n\nsb.write_string('\\n')\nsb.write_string('pub fn (typ ${node_type_enum_name}) group() ${super_type_enum_name} {')\nsb.write_string('   return ')\n\nsupertype_ordered_names := [\n\t'top_level_declaration',\n\t'expression',\n\t'statement',\n\t'unknown',\n]\nmut super_type_index := 0\nfor supertype_name in supertype_ordered_names {\n\tif super_type_index < supertype_ordered_names.len - 1 {\n\t\tsb.write_string('if typ in supertype__${supertype_name}_nodes ')\n\t}\n\tsb.write_string('{\\n      ')\n\twrite_enum_member(mut sb, super_type_enum_name, supertype_name)\n\tsb.write_string('\\n   }')\n\tif super_type_index < supertype_ordered_names.len - 1 {\n\t\tsb.write_string(' else ')\n\t} else {\n\t\tsb.write_u8(`\\n`)\n\t}\n\tsuper_type_index++\n}\nsb.writeln('}')\n\n// write constants\nwrite_const_enum_array(mut sb, 'declaration_node_types', node_type_enum_name,\n\tdeclaration_node_types)\nwrite_const_enum_array(mut sb, 'identifier_node_types', node_type_enum_name, identifier_node_types)\nwrite_const_enum_array(mut sb, 'literal_node_types', node_type_enum_name, literal_node_types)\n\nsb.writeln('\\n')\nsb.writeln('pub fn (typ ${node_type_enum_name}) is_declaration() bool { return typ in declaration_node_types }')\nsb.writeln('pub fn (typ ${node_type_enum_name}) is_identifier() bool { return typ in identifier_node_types }')\nsb.writeln('pub fn (typ ${node_type_enum_name}) is_literal() bool { return typ in literal_node_types }')\n\n// create VNodeTypeFactory\nnode_type_factory_sym_name := 'VNodeTypeFactory'\n\nsb.writeln('\\n')\nsb.writeln('pub const type_factory = &${node_type_factory_sym_name}{}')\nsb.writeln('\\n')\nsb.writeln('pub struct ${node_type_factory_sym_name} {}')\nsb.writeln('\\n')\nsb.writeln('pub fn (nf ${node_type_factory_sym_name}) get_type(type_name string) ${node_type_enum_name} {')\nsb.writeln('   return bindings.node_type_name_to_enum[type_name] or { NodeType.unknown }')\nsb.writeln('}')\nsb.writeln('\\n')\nsb.writeln('const node_type_name_to_enum = {')\nsb.write_string(\"      'ERROR': ${node_type_enum_name}.error\")\nfor node_type in node_types {\n\tif node_type.is_anon() {\n\t\tcontinue\n\t}\n\tsb.write_string(\"      '${node_type.name}': \")\n\twrite_enum_member(mut sb, node_type_enum_name, node_type.name)\n\tsb.writeln('')\n}\nsb.writeln('}')\n\nfile.write(sb)!\nfile.close()\n\nres := os.execute('v fmt -w ${file_path}')\nif res.exit_code != 0 {\n\tpanic('v fmt failed:\\n\\n${res.output}')\n}\n\nprintln('Successfully generated `${file_path}`')\n"
  },
  {
    "path": "tree_sitter_v/bindings/node_types.v",
    "content": "// This is an AUTO-GENERATED file. DO NOT EDIT this file directly! See `generate_types.vsh`\nmodule bindings\n\nimport arrays { merge }\n\npub enum SuperType {\n\tunknown\n\texpression\n\texpression_with_blocks\n\tstatement\n\ttop_level_declaration\n}\n\npub enum NodeType {\n\tunknown\n\terror\n\tanon_struct_type\n\tanon_struct_value_expression\n\tappend_statement\n\targument\n\targument_list\n\tarray_creation\n\tarray_type\n\tas_type_cast_expression\n\tasm_statement\n\tassert_statement\n\tassignment_statement\n\tatomic_type\n\tattribute\n\tattribute_expression\n\tattributes\n\tbinary_expression\n\tblock\n\tblock_comment\n\tbreak_statement\n\tc_string_literal\n\tcall_expression\n\tcapture\n\tcapture_list\n\tchannel_type\n\tcompile_time_for_statement\n\tcompile_time_if_expression\n\tcompile_time_selector_expression\n\tconst_declaration\n\tconst_definition\n\tcontinue_statement\n\tdec_expression\n\tdefer_statement\n\telement_list\n\telse_branch\n\tembedded_definition\n\tenum_backed_type\n\tenum_declaration\n\tenum_fetch\n\tenum_field_definition\n\texpression_list\n\tfield_name\n\tfixed_array_creation\n\tfixed_array_type\n\tfor_clause\n\tfor_statement\n\tformat_specifier\n\tfunction_declaration\n\tfunction_literal\n\tfunction_type\n\tgeneric_parameter\n\tgeneric_parameters\n\tgeneric_type\n\tglobal_var_declaration\n\tglobal_var_definition\n\tgo_expression\n\tgoto_statement\n\thash_statement\n\tidentifier_list\n\tif_attribute\n\tif_expression\n\timplements_clause\n\timport_alias\n\timport_declaration\n\timport_list\n\timport_name\n\timport_path\n\timport_spec\n\tin_expression\n\tinc_expression\n\tindex_expression\n\tinterface_declaration\n\tinterface_method_definition\n\tinterpreted_string_literal\n\tis_clause\n\tis_expression\n\tkey_value_attribute\n\tkeyed_element\n\tlabel_definition\n\tlabel_reference\n\tlabeled_statement\n\tline_comment\n\tliteral\n\tliteral_attribute\n\tlock_expression\n\tmap_init_expression\n\tmap_keyed_element\n\tmap_type\n\tmatch_arm\n\tmatch_arm_type\n\tmatch_arms\n\tmatch_else_arm_clause\n\tmatch_expression\n\tmatch_expression_list\n\tmodule_clause\n\tmulti_return_type\n\tmutability_modifiers\n\tmutable_expression\n\tmutable_identifier\n\toption_propagation_expression\n\toption_type\n\tor_block\n\tor_block_expression\n\toverridable_operator\n\tparameter_declaration\n\tparameter_list\n\tparenthesized_expression\n\tplain_type\n\tpointer_type\n\tqualified_type\n\trange\n\trange_clause\n\traw_string_literal\n\treceive_expression\n\treceiver\n\treference_expression\n\tresult_propagation_expression\n\tresult_type\n\treturn_statement\n\tselect_arm\n\tselect_arm_statement\n\tselect_else_arn_clause\n\tselect_expression\n\tselective_import_list\n\tselector_expression\n\tsend_statement\n\tshared_type\n\tshebang\n\tshort_element_list\n\tshort_lambda\n\tsignature\n\tsimple_statement\n\tslice_expression\n\tsource_file\n\tspawn_expression\n\tspecial_argument_list\n\tspread_expression\n\tsql_expression\n\tstatic_method_declaration\n\tstatic_receiver\n\tstring_interpolation\n\tstruct_declaration\n\tstruct_field_declaration\n\tstruct_field_scope\n\tsum_type\n\tthread_type\n\ttype_declaration\n\ttype_initializer\n\ttype_initializer_body\n\ttype_parameter_declaration\n\ttype_parameter_list\n\ttype_parameters\n\ttype_reference_expression\n\tunary_expression\n\tunsafe_expression\n\tvalue_attribute\n\tvar_declaration\n\tvar_definition\n\tvar_definition_list\n\tvariadic_parameter\n\tvisibility_modifiers\n\twrong_pointer_type\n\tescape_sequence\n\tfalse_\n\tfloat_literal\n\tidentifier\n\tint_literal\n\tinterpolation_closing\n\tinterpolation_opening\n\tnil_\n\tnone_\n\tpseudo_compile_time_identifier\n\trune_literal\n\ttrue_\n}\n\nconst supertype__expression_nodes = merge(supertype__expression_with_blocks_nodes, [\n\tNodeType.array_creation,\n\t.as_type_cast_expression,\n\t.binary_expression,\n\t.call_expression,\n\t.dec_expression,\n\t.enum_fetch,\n\t.fixed_array_creation,\n\t.function_literal,\n\t.go_expression,\n\t.in_expression,\n\t.inc_expression,\n\t.index_expression,\n\t.is_expression,\n\t.literal,\n\t.option_propagation_expression,\n\t.or_block_expression,\n\t.parenthesized_expression,\n\t.pseudo_compile_time_identifier,\n\t.receive_expression,\n\t.reference_expression,\n\t.result_propagation_expression,\n\t.selector_expression,\n\t.slice_expression,\n\t.spawn_expression,\n\t.unary_expression,\n])\n\nconst supertype__expression_with_blocks_nodes = [\n\tNodeType.anon_struct_value_expression,\n\t.compile_time_if_expression,\n\t.if_expression,\n\t.lock_expression,\n\t.map_init_expression,\n\t.match_expression,\n\t.select_expression,\n\t.sql_expression,\n\t.type_initializer,\n\t.unsafe_expression,\n]\n\nconst supertype__statement_nodes = [\n\tNodeType.append_statement,\n\t.asm_statement,\n\t.assert_statement,\n\t.block,\n\t.break_statement,\n\t.compile_time_for_statement,\n\t.continue_statement,\n\t.defer_statement,\n\t.for_statement,\n\t.goto_statement,\n\t.hash_statement,\n\t.labeled_statement,\n\t.return_statement,\n\t.send_statement,\n\t.simple_statement,\n]\n\nconst supertype__top_level_declaration_nodes = [\n\tNodeType.const_declaration,\n\t.enum_declaration,\n\t.function_declaration,\n\t.global_var_declaration,\n\t.interface_declaration,\n\t.static_method_declaration,\n\t.struct_declaration,\n\t.type_declaration,\n]\n\npub fn (typ NodeType) group() SuperType {\n\treturn if typ in supertype__top_level_declaration_nodes {\n\t\tSuperType.top_level_declaration\n\t} else if typ in supertype__expression_nodes {\n\t\tSuperType.expression\n\t} else if typ in supertype__statement_nodes {\n\t\tSuperType.statement\n\t} else {\n\t\tSuperType.unknown\n\t}\n}\n\nconst declaration_node_types = [\n\tNodeType.const_declaration,\n\t.enum_declaration,\n\t.function_declaration,\n\t.global_var_declaration,\n\t.import_declaration,\n\t.interface_declaration,\n\t.parameter_declaration,\n\t.static_method_declaration,\n\t.struct_declaration,\n\t.struct_field_declaration,\n\t.type_declaration,\n\t.type_parameter_declaration,\n\t.var_declaration,\n]\n\nconst identifier_node_types = [\n\tNodeType.mutable_identifier,\n\t.identifier,\n\t.pseudo_compile_time_identifier,\n]\n\nconst literal_node_types = [\n\tNodeType.c_string_literal,\n\t.function_literal,\n\t.interpreted_string_literal,\n\t.raw_string_literal,\n\t.float_literal,\n\t.int_literal,\n\t.rune_literal,\n]\n\npub fn (typ NodeType) is_declaration() bool {\n\treturn typ in declaration_node_types\n}\n\npub fn (typ NodeType) is_identifier() bool {\n\treturn typ in identifier_node_types\n}\n\npub fn (typ NodeType) is_literal() bool {\n\treturn typ in literal_node_types\n}\n\npub const type_factory = &VNodeTypeFactory{}\n\npub struct VNodeTypeFactory {}\n\npub fn (nf VNodeTypeFactory) get_type(type_name string) NodeType {\n\treturn node_type_name_to_enum[type_name] or { NodeType.unknown }\n}\n\nconst node_type_name_to_enum = {\n\t'ERROR':                            NodeType.error\n\t'anon_struct_type':                 NodeType.anon_struct_type\n\t'anon_struct_value_expression':     NodeType.anon_struct_value_expression\n\t'append_statement':                 NodeType.append_statement\n\t'argument':                         NodeType.argument\n\t'argument_list':                    NodeType.argument_list\n\t'array_creation':                   NodeType.array_creation\n\t'array_type':                       NodeType.array_type\n\t'as_type_cast_expression':          NodeType.as_type_cast_expression\n\t'asm_statement':                    NodeType.asm_statement\n\t'assert_statement':                 NodeType.assert_statement\n\t'assignment_statement':             NodeType.assignment_statement\n\t'atomic_type':                      NodeType.atomic_type\n\t'attribute':                        NodeType.attribute\n\t'attribute_expression':             NodeType.attribute_expression\n\t'attributes':                       NodeType.attributes\n\t'binary_expression':                NodeType.binary_expression\n\t'block':                            NodeType.block\n\t'block_comment':                    NodeType.block_comment\n\t'break_statement':                  NodeType.break_statement\n\t'c_string_literal':                 NodeType.c_string_literal\n\t'call_expression':                  NodeType.call_expression\n\t'capture':                          NodeType.capture\n\t'capture_list':                     NodeType.capture_list\n\t'channel_type':                     NodeType.channel_type\n\t'compile_time_for_statement':       NodeType.compile_time_for_statement\n\t'compile_time_if_expression':       NodeType.compile_time_if_expression\n\t'compile_time_selector_expression': NodeType.compile_time_selector_expression\n\t'const_declaration':                NodeType.const_declaration\n\t'const_definition':                 NodeType.const_definition\n\t'continue_statement':               NodeType.continue_statement\n\t'dec_expression':                   NodeType.dec_expression\n\t'defer_statement':                  NodeType.defer_statement\n\t'element_list':                     NodeType.element_list\n\t'else_branch':                      NodeType.else_branch\n\t'embedded_definition':              NodeType.embedded_definition\n\t'enum_backed_type':                 NodeType.enum_backed_type\n\t'enum_declaration':                 NodeType.enum_declaration\n\t'enum_fetch':                       NodeType.enum_fetch\n\t'enum_field_definition':            NodeType.enum_field_definition\n\t'expression_list':                  NodeType.expression_list\n\t'field_name':                       NodeType.field_name\n\t'fixed_array_creation':             NodeType.fixed_array_creation\n\t'fixed_array_type':                 NodeType.fixed_array_type\n\t'for_clause':                       NodeType.for_clause\n\t'for_statement':                    NodeType.for_statement\n\t'format_specifier':                 NodeType.format_specifier\n\t'function_declaration':             NodeType.function_declaration\n\t'function_literal':                 NodeType.function_literal\n\t'function_type':                    NodeType.function_type\n\t'generic_parameter':                NodeType.generic_parameter\n\t'generic_parameters':               NodeType.generic_parameters\n\t'generic_type':                     NodeType.generic_type\n\t'global_var_declaration':           NodeType.global_var_declaration\n\t'global_var_definition':            NodeType.global_var_definition\n\t'go_expression':                    NodeType.go_expression\n\t'goto_statement':                   NodeType.goto_statement\n\t'hash_statement':                   NodeType.hash_statement\n\t'identifier_list':                  NodeType.identifier_list\n\t'if_attribute':                     NodeType.if_attribute\n\t'if_expression':                    NodeType.if_expression\n\t'implements_clause':                NodeType.implements_clause\n\t'import_alias':                     NodeType.import_alias\n\t'import_declaration':               NodeType.import_declaration\n\t'import_list':                      NodeType.import_list\n\t'import_name':                      NodeType.import_name\n\t'import_path':                      NodeType.import_path\n\t'import_spec':                      NodeType.import_spec\n\t'in_expression':                    NodeType.in_expression\n\t'inc_expression':                   NodeType.inc_expression\n\t'index_expression':                 NodeType.index_expression\n\t'interface_declaration':            NodeType.interface_declaration\n\t'interface_method_definition':      NodeType.interface_method_definition\n\t'interpreted_string_literal':       NodeType.interpreted_string_literal\n\t'is_clause':                        NodeType.is_clause\n\t'is_expression':                    NodeType.is_expression\n\t'key_value_attribute':              NodeType.key_value_attribute\n\t'keyed_element':                    NodeType.keyed_element\n\t'label_definition':                 NodeType.label_definition\n\t'label_reference':                  NodeType.label_reference\n\t'labeled_statement':                NodeType.labeled_statement\n\t'line_comment':                     NodeType.line_comment\n\t'literal':                          NodeType.literal\n\t'literal_attribute':                NodeType.literal_attribute\n\t'lock_expression':                  NodeType.lock_expression\n\t'map_init_expression':              NodeType.map_init_expression\n\t'map_keyed_element':                NodeType.map_keyed_element\n\t'map_type':                         NodeType.map_type\n\t'match_arm':                        NodeType.match_arm\n\t'match_arm_type':                   NodeType.match_arm_type\n\t'match_arms':                       NodeType.match_arms\n\t'match_else_arm_clause':            NodeType.match_else_arm_clause\n\t'match_expression':                 NodeType.match_expression\n\t'match_expression_list':            NodeType.match_expression_list\n\t'module_clause':                    NodeType.module_clause\n\t'multi_return_type':                NodeType.multi_return_type\n\t'mutability_modifiers':             NodeType.mutability_modifiers\n\t'mutable_expression':               NodeType.mutable_expression\n\t'mutable_identifier':               NodeType.mutable_identifier\n\t'option_propagation_expression':    NodeType.option_propagation_expression\n\t'option_type':                      NodeType.option_type\n\t'or_block':                         NodeType.or_block\n\t'or_block_expression':              NodeType.or_block_expression\n\t'overridable_operator':             NodeType.overridable_operator\n\t'parameter_declaration':            NodeType.parameter_declaration\n\t'parameter_list':                   NodeType.parameter_list\n\t'parenthesized_expression':         NodeType.parenthesized_expression\n\t'plain_type':                       NodeType.plain_type\n\t'pointer_type':                     NodeType.pointer_type\n\t'qualified_type':                   NodeType.qualified_type\n\t'range':                            NodeType.range\n\t'range_clause':                     NodeType.range_clause\n\t'raw_string_literal':               NodeType.raw_string_literal\n\t'receive_expression':               NodeType.receive_expression\n\t'receiver':                         NodeType.receiver\n\t'reference_expression':             NodeType.reference_expression\n\t'result_propagation_expression':    NodeType.result_propagation_expression\n\t'result_type':                      NodeType.result_type\n\t'return_statement':                 NodeType.return_statement\n\t'select_arm':                       NodeType.select_arm\n\t'select_arm_statement':             NodeType.select_arm_statement\n\t'select_else_arn_clause':           NodeType.select_else_arn_clause\n\t'select_expression':                NodeType.select_expression\n\t'selective_import_list':            NodeType.selective_import_list\n\t'selector_expression':              NodeType.selector_expression\n\t'send_statement':                   NodeType.send_statement\n\t'shared_type':                      NodeType.shared_type\n\t'shebang':                          NodeType.shebang\n\t'short_element_list':               NodeType.short_element_list\n\t'short_lambda':                     NodeType.short_lambda\n\t'signature':                        NodeType.signature\n\t'simple_statement':                 NodeType.simple_statement\n\t'slice_expression':                 NodeType.slice_expression\n\t'source_file':                      NodeType.source_file\n\t'spawn_expression':                 NodeType.spawn_expression\n\t'special_argument_list':            NodeType.special_argument_list\n\t'spread_expression':                NodeType.spread_expression\n\t'sql_expression':                   NodeType.sql_expression\n\t'static_method_declaration':        NodeType.static_method_declaration\n\t'static_receiver':                  NodeType.static_receiver\n\t'string_interpolation':             NodeType.string_interpolation\n\t'struct_declaration':               NodeType.struct_declaration\n\t'struct_field_declaration':         NodeType.struct_field_declaration\n\t'struct_field_scope':               NodeType.struct_field_scope\n\t'sum_type':                         NodeType.sum_type\n\t'thread_type':                      NodeType.thread_type\n\t'type_declaration':                 NodeType.type_declaration\n\t'type_initializer':                 NodeType.type_initializer\n\t'type_initializer_body':            NodeType.type_initializer_body\n\t'type_parameter_declaration':       NodeType.type_parameter_declaration\n\t'type_parameter_list':              NodeType.type_parameter_list\n\t'type_parameters':                  NodeType.type_parameters\n\t'type_reference_expression':        NodeType.type_reference_expression\n\t'unary_expression':                 NodeType.unary_expression\n\t'unsafe_expression':                NodeType.unsafe_expression\n\t'value_attribute':                  NodeType.value_attribute\n\t'var_declaration':                  NodeType.var_declaration\n\t'var_definition':                   NodeType.var_definition\n\t'var_definition_list':              NodeType.var_definition_list\n\t'variadic_parameter':               NodeType.variadic_parameter\n\t'visibility_modifiers':             NodeType.visibility_modifiers\n\t'wrong_pointer_type':               NodeType.wrong_pointer_type\n\t'escape_sequence':                  NodeType.escape_sequence\n\t'false':                            NodeType.false_\n\t'float_literal':                    NodeType.float_literal\n\t'identifier':                       NodeType.identifier\n\t'int_literal':                      NodeType.int_literal\n\t'interpolation_closing':            NodeType.interpolation_closing\n\t'interpolation_opening':            NodeType.interpolation_opening\n\t'nil':                              NodeType.nil_\n\t'none':                             NodeType.none_\n\t'pseudo_compile_time_identifier':   NodeType.pseudo_compile_time_identifier\n\t'rune_literal':                     NodeType.rune_literal\n\t'true':                             NodeType.true_\n}\n"
  },
  {
    "path": "tree_sitter_v/bindings/simple_test.v",
    "content": "module bindings\n\nfn test_simple() {\n\tmut p := new_parser[NodeType](type_factory)\n\tp.set_language(language)\n\n\tcode := 'fn main() {}'\n\ttree := p.parse_string(source: code)\n\troot := tree.root_node()\n\n\tprintln(root)\n\n\tfc := root.first_child()?\n\n\tif fc.type_name == .function_declaration {\n\t\tif name_node := fc.child_by_field_name('name') {\n\t\t\tassert name_node.text(code) == 'main'\n\t\t\tassert name_node.range().start_point.row == 0\n\t\t\tassert name_node.range().start_point.column == 3\n\t\t\tassert name_node.range().end_point.row == 0\n\t\t\tassert name_node.range().end_point.column == 7\n\t\t} else {\n\t\t\tassert false, 'name node not found'\n\t\t}\n\t} else {\n\t\tassert false, 'function declaration not found'\n\t}\n}\n"
  },
  {
    "path": "tree_sitter_v/examples/cursor.v",
    "content": "module main\n\nimport bindings\n\nfn main() {\n\tmut p := bindings.new_parser[bindings.NodeType](bindings.type_factory)\n\tp.set_language(bindings.language)\n\n\tcode := '\nfn foo() int {\n\treturn 1\n}\n'.trim_indent()\n\n\ttree := p.parse_string(source: code)\n\troot := tree.root_node()\n\n\tmut cursor := root.tree_cursor()\n\tcursor.to_first_child() // go to all the children of the root node\n\tcursor.to_first_child() // go to the first child of the function node\n\n\tfor {\n\t\tnode := cursor.current_node() or { break }\n\n\t\tprintln('Node \"${node.type_name}\" with text: ' + node.text(code))\n\n\t\tif !cursor.next() {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "tree_sitter_v/examples/simple.v",
    "content": "module main\n\nimport bindings\n\nfn main() {\n\tmut p := bindings.new_parser[bindings.NodeType](bindings.type_factory)\n\tp.set_language(bindings.language)\n\n\tcode := 'fn main() {}'\n\ttree := p.parse_string(source: code)\n\troot := tree.root_node()\n\n\tprintln(root)\n\n\tfc := root.first_child()?\n\n\tif fc.type_name == .function_declaration {\n\t\tif name_node := fc.child_by_field_name('name') {\n\t\t\tprintln('Found function: ${name_node.text(code)}')\n\t\t\tprintln('Position: ${name_node.range()}')\n\t\t\tprintln('Line: ${name_node.start_point().row}')\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "tree_sitter_v/examples/with_old_tree.v",
    "content": "module main\n\nimport time\nimport bindings\n\nfn main() {\n\tmut p := bindings.new_parser[bindings.NodeType](bindings.type_factory)\n\tp.set_language(bindings.language)\n\n\tcode := '\nfn foo() int {\n\treturn 1\n}\n'.trim_indent()\n\n\tmut now := time.now()\n\ttree := p.parse_string(source: code)\n\tprintln('Parsed in ${time.since(now)}')\n\n\troot := tree.root_node()\n\tprintln(root)\n\n\tnew_code := '\nfn foo() int {\n\treturn 2\n}\n'.trim_indent()\n\n\tnow = time.now()\n\tnew_tree := p.parse_string(source: new_code, tree: tree.raw_tree)\n\tprintln('Parsed in ${time.since(now)}')\n\n\tnew_root := new_tree.root_node()\n\tprintln(new_root)\n}\n"
  },
  {
    "path": "tree_sitter_v/grammar.js",
    "content": "/**\n * @file V grammar for tree-sitter\n */\n\n/* eslint-disable no-undef */\n/* eslint-disable arrow-parens */\n/* eslint-disable camelcase */\n/* eslint-disable-next-line spaced-comment */\n/// <reference types=\"tree-sitter-cli/dsl\" />\n\nconst PREC = {\n\tattributes: 10,\n\tmatch_arm_type: 9,\n\ttype_initializer: 8,\n\tprimary: 7,\n\tunary: 6,\n\tmultiplicative: 5,\n\tadditive: 4,\n\tcomparative: 3,\n\tand: 2,\n\tor: 1,\n\tresolve: 1,\n\tcomposite_literal: -1,\n\tstrictly_expression_list: -2,\n};\n\nconst multiplicative_operators = ['*', '/', '%', '<<', '>>', '>>>', '&', '&^'];\nconst additive_operators = ['+', '-', '|', '^'];\nconst comparative_operators = ['==', '!=', '<', '<=', '>', '>='];\nconst assignment_operators = multiplicative_operators\n\t.concat(additive_operators)\n\t.map((operator) => operator + '=')\n\t.concat('=');\nconst unary_operators = ['+', '-', '!', '~', '^', '*', '&'];\nconst overridable_operators = ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '<=', '>='].map(\n\t(operator) => token(operator),\n);\n\nconst terminator = choice('\\n', '\\r', '\\r\\n');\n\nconst unicode_digit = /[0-9]/;\nconst unicode_letter = /[a-zA-Zα-ωΑ-Ωµ]/;\n\nconst letter = choice(unicode_letter, '_');\n\nconst hex_digit = /[0-9a-fA-F]/;\nconst octal_digit = /[0-7]/;\nconst decimal_digit = /[0-9]/;\nconst binary_digit = /[01]/;\n\nconst hex_digits = seq(hex_digit, repeat(seq(optional('_'), hex_digit)));\nconst octal_digits = seq(octal_digit, repeat(seq(optional('_'), octal_digit)));\nconst decimal_digits = seq(decimal_digit, repeat(seq(optional('_'), decimal_digit)));\nconst binary_digits = seq(binary_digit, repeat(seq(optional('_'), binary_digit)));\n\nconst hex_literal = seq('0', choice('x', 'X'), optional('_'), hex_digits);\nconst octal_literal = seq('0', optional(choice('o', 'O')), optional('_'), octal_digits);\nconst decimal_literal = choice('0', seq(/[1-9]/, optional(seq(optional('_'), decimal_digits))));\nconst binary_literal = seq('0', choice('b', 'B'), optional('_'), binary_digits);\n\nconst int_literal = choice(binary_literal, decimal_literal, octal_literal, hex_literal);\n\nconst decimal_exponent = seq(choice('e', 'E'), optional(choice('+', '-')), decimal_digits);\nconst decimal_float_literal = choice(\n\tseq(decimal_digits, '.', decimal_digits, optional(decimal_exponent)),\n\tseq(decimal_digits, decimal_exponent),\n\tseq('.', decimal_digits, optional(decimal_exponent)),\n);\n\nconst hex_exponent = seq(choice('p', 'P'), optional(choice('+', '-')), decimal_digits);\nconst hex_mantissa = choice(\n\tseq(optional('_'), hex_digits, '.', optional(hex_digits)),\n\tseq(optional('_'), hex_digits),\n\tseq('.', hex_digits),\n);\nconst hex_float_literal = seq('0', choice('x', 'X'), hex_mantissa, hex_exponent);\nconst float_literal = choice(decimal_float_literal, hex_float_literal);\n\nconst format_flag = token(/[bgGeEfFcdoxXpsS]/);\n\nconst semi = choice(terminator, ';');\nconst list_separator = choice(semi, ',');\n\nmodule.exports = grammar({\n\tname: 'v',\n\n\textras: ($) => [/\\s/, $.line_comment, $.block_comment],\n\n\tword: ($) => $.identifier,\n\n\texternals: (_) => [],\n\n\tinline: ($) => [$._string_literal, $._top_level_declaration, $._array],\n\n\tsupertypes: ($) => [\n\t\t$._expression,\n\t\t$._statement,\n\t\t$._top_level_declaration,\n\t\t$._expression_with_blocks,\n\t],\n\n\tconflicts: ($) => [\n\t\t[$.fixed_array_type, $._expression_without_blocks],\n\t\t[$.qualified_type, $._expression_without_blocks],\n\t\t[$.fixed_array_type, $.literal],\n\t\t[$.reference_expression, $.type_reference_expression],\n\t\t[$.is_expression],\n\t\t[$._expression_without_blocks, $.element_list],\n\t],\n\n\trules: {\n\t\tsource_file: ($) =>\n\t\t\tseq(\n\t\t\t\toptional($.shebang),\n\t\t\t\toptional($.module_clause),\n\t\t\t\trepeat(\n\t\t\t\t\tchoice(\n\t\t\t\t\t\tseq($.import_list, optional(terminator)),\n\t\t\t\t\t\tseq($._top_level_declaration, optional(terminator)),\n\t\t\t\t\t\tseq($._statement, optional(terminator)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\tshebang: (_) => seq('#!', /.*/),\n\n\t\tline_comment: (_) => seq('//', /.*/),\n\n\t\tblock_comment: (_) =>\n\t\t\tseq(\n\t\t\t\t'/*',\n\t\t\t\trepeat(\n\t\t\t\t\tchoice(\n\t\t\t\t\t\t/\\*/,\n\t\t\t\t\t\tregexOr(\n\t\t\t\t\t\t\t'[^*]', // any symbol except reserved\n\t\t\t\t\t\t\t'[/][^*]', // start of nested comment\n\t\t\t\t\t\t\t'[^*][/]', // end of nested comment\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t'*/',\n\t\t\t),\n\n\t\tcomment: ($) => choice($.line_comment, $.block_comment),\n\n\t\tmodule_clause: ($) => seq(optional($.attributes), 'module', $.identifier),\n\n\t\timport_list: ($) => prec.right(repeat1($.import_declaration)),\n\n\t\timport_declaration: ($) => seq('import', $.import_spec, semi),\n\n\t\timport_spec: ($) =>\n\t\t\tseq($.import_path, optional($.import_alias), optional($.selective_import_list)),\n\n\t\t// foo.bar.baz\n\t\timport_path: ($) => seq($.import_name, repeat(seq('.', $.import_name))),\n\n\t\t// foo\n\t\timport_name: ($) => $.identifier,\n\n\t\t// foo as bar\n\t\t//     ^^^^^^\n\t\timport_alias: ($) => seq('as', $.import_name),\n\n\t\t// { foo, bar }\n\t\tselective_import_list: ($) =>\n\t\t\tseq(\n\t\t\t\t'{',\n\t\t\t\t$.reference_expression,\n\t\t\t\trepeat(seq(choice(',', terminator), optional($.reference_expression))),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\t// ==================== TOP LEVEL DECLARATIONS ====================\n\n\t\t_top_level_declaration: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.const_declaration,\n\t\t\t\t$.global_var_declaration,\n\t\t\t\t$.type_declaration,\n\t\t\t\t$.function_declaration,\n\t\t\t\t$.static_method_declaration,\n\t\t\t\t$.struct_declaration,\n\t\t\t\t$.enum_declaration,\n\t\t\t\t$.interface_declaration,\n\t\t\t),\n\n\t\tconst_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t'const',\n\t\t\t\tchoice($.const_definition, seq('(', repeat(seq($.const_definition, semi)), ')')),\n\t\t\t),\n\n\t\tconst_definition: ($) => seq(field('name', $.identifier), '=', field('value', $._expression)),\n\n\t\tglobal_var_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\t'__global',\n\t\t\t\tchoice($.global_var_definition, seq('(', repeat(seq($.global_var_definition, semi)), ')')),\n\t\t\t),\n\n\t\tglobal_var_definition: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('modifiers', 'volatile')),\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\tchoice($.plain_type, $._global_var_value),\n\t\t\t),\n\n\t\t_global_var_value: ($) => seq('=', field('value', $._expression)),\n\n\t\ttype_declaration: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.resolve,\n\t\t\t\tseq(\n\t\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t\t'type',\n\t\t\t\t\tfield('name', $.identifier),\n\t\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t\t'=',\n\t\t\t\t\tfield('type', choice($.sum_type, $.plain_type)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tfunction_declaration: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.resolve,\n\t\t\t\tseq(\n\t\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t\t'fn',\n\t\t\t\t\toptional(field('receiver', $.receiver)),\n\t\t\t\t\tfield('name', $._function_name),\n\t\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t\tfield('signature', $.signature),\n\t\t\t\t\toptional(field('body', $.block)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tstatic_method_declaration: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.resolve,\n\t\t\t\tseq(\n\t\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t\t'fn',\n\t\t\t\t\tfield('static_receiver', $.static_receiver),\n\t\t\t\t\t'.',\n\t\t\t\t\tfield('name', $._function_name),\n\t\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t\tfield('signature', $.signature),\n\t\t\t\t\toptional(field('body', $.block)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tstatic_receiver: ($) => $.reference_expression,\n\n\t\t_function_name: ($) => choice($.identifier, $.overridable_operator),\n\n\t\toverridable_operator: () => choice(...overridable_operators),\n\n\t\treceiver: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.primary,\n\t\t\t\tseq(\n\t\t\t\t\t'(',\n\t\t\t\t\tseq(\n\t\t\t\t\t\toptional(field('mutability', $.mutability_modifiers)),\n\t\t\t\t\t\tfield('name', $.identifier),\n\t\t\t\t\t\tfield('type', alias($._plain_type_without_special, $.plain_type)),\n\t\t\t\t\t),\n\t\t\t\t\t')',\n\t\t\t\t),\n\t\t\t),\n\n\t\tsignature: ($) =>\n\t\t\tprec.right(\n\t\t\t\tseq(\n\t\t\t\t\tfield('parameters', choice($.parameter_list, $.type_parameter_list)),\n\t\t\t\t\toptional(field('result', $.plain_type)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tparameter_list: ($) =>\n    \t\tprec(PREC.resolve, seq(\n    \t\t    '(',\n    \t\t    optional(choice(\n    \t\t        $.variadic_parameter,\n    \t\t        seq(\n    \t\t            sep($.parameter_declaration),\n    \t\t            optional(seq(',', $.variadic_parameter))\n    \t\t        )\n    \t\t    )),\n    \t\t    ')'\n    \t\t)),\n\n\t\tparameter_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('mutability', $.mutability_modifiers)),\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\toptional(field('variadic', '...')),\n\t\t\t\tfield('type', $.plain_type),\n\t\t\t),\n\n\t\tvariadic_parameter: ($) => '...',\n\n\t\ttype_parameter_list: ($) => seq('(', sep($.type_parameter_declaration), ')'),\n\n\t\ttype_parameter_declaration: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.primary,\n\t\t\t\tseq(\n\t\t\t\t\toptional($.mutability_modifiers),\n\t\t\t\t\toptional(field('variadic', '...')),\n\t\t\t\t\tfield('type', $.plain_type),\n\t\t\t\t),\n\t\t\t),\n\n\t\t// fn foo[T, T2]() {}\n\t\t//       ^^^^^^^\n\t\tgeneric_parameters: ($) =>\n    \t\tseq(\n    \t\t    token.immediate('['),\n    \t\t    sep($.generic_parameter),\n    \t\t    optional(','),\n    \t\t    ']',\n    \t\t),\n\n\t\tgeneric_parameter: ($) => $.identifier,\n\n\t\tstruct_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\tchoice('struct', 'union'),\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\toptional(seq('implements', field('implements', $.implements_clause))),\n\t\t\t\t$._struct_body,\n\t\t\t),\n\n\t\timplements_clause: ($) =>\n\t\t\tseq(\n\t\t\t\tchoice($.type_reference_expression, $.qualified_type),\n\t\t\t\trepeat(seq(',', choice($.type_reference_expression, $.qualified_type))),\n\t\t\t),\n\n\t\t_struct_body: ($) =>\n\t\t\tseq(\n\t\t\t\t'{',\n\t\t\t\trepeat(\n\t\t\t\t\tchoice(\n\t\t\t\t\t\tseq($.struct_field_scope, optional(terminator)),\n\t\t\t\t\t\tseq($.struct_field_declaration, optional(terminator)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\t// pub:\n\t\t// mut:\n\t\t// pub mut:\n\t\t// __global:\n\t\tstruct_field_scope: () => seq(choice('pub', 'mut', seq('pub', 'mut'), '__global'), ':'),\n\n\t\tstruct_field_declaration: ($) => choice($._struct_field_definition, $.embedded_definition),\n\n\t\t_struct_field_definition: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.type_initializer,\n\t\t\t\tseq(\n\t\t\t\t\tfield('name', $.identifier),\n\t\t\t\t\tfield('type', $.plain_type),\n\t\t\t\t\toptional(seq('=', field('default_value', $._expression))),\n\t\t\t\t\toptional(field('attributes', $.attribute)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tembedded_definition: ($) =>\n\t\t\tchoice($.type_reference_expression, $.qualified_type, $.generic_type),\n\n\t\tenum_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t'enum',\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\toptional($.enum_backed_type),\n\t\t\t\t$._enum_body,\n\t\t\t),\n\n\t\tenum_backed_type: ($) => seq('as', $.plain_type),\n\n\t\t_enum_body: ($) => seq('{', repeat(seq($.enum_field_definition, optional(terminator))), '}'),\n\n\t\tenum_field_definition: ($) =>\n\t\t\tseq(\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\toptional(seq('=', field('value', $._expression))),\n\t\t\t\toptional(field('attributes', $.attribute)),\n\t\t\t),\n\n\t\tinterface_declaration: ($) =>\n\t\t\tseq(\n\t\t\t\toptional(field('attributes', $.attributes)),\n\t\t\t\toptional($.visibility_modifiers),\n\t\t\t\t'interface',\n\t\t\t\tfield('name', $.identifier),\n\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t$._interface_body,\n\t\t\t),\n\n\t\t_interface_body: ($) =>\n\t\t\tseq(\n\t\t\t\t'{',\n\t\t\t\trepeat(\n\t\t\t\t\tchoice(\n\t\t\t\t\t\tseq($.struct_field_scope, optional(terminator)),\n\t\t\t\t\t\tseq($.struct_field_declaration, optional(terminator)),\n\t\t\t\t\t\tseq($.interface_method_definition, optional(terminator)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\tinterface_method_definition: ($) =>\n\t\t\tprec.right(\n\t\t\t\tseq(\n\t\t\t\t\tfield('name', $.identifier),\n\t\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t\tfield('signature', $.signature),\n\t\t\t\t\toptional(field('attributes', $.attribute)),\n\t\t\t\t),\n\t\t\t),\n\n\t\t// ==================== EXPRESSIONS ====================\n\n\t\t_expression: ($) => choice($._expression_without_blocks, $._expression_with_blocks),\n\n\t\t_expression_without_blocks: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.parenthesized_expression,\n\t\t\t\t$.go_expression,\n\t\t\t\t$.spawn_expression,\n\t\t\t\t$.call_expression,\n\t\t\t\t$.function_literal,\n\t\t\t\t$.reference_expression,\n\t\t\t\t$._max_group,\n\t\t\t\t$.array_creation,\n\t\t\t\t$.fixed_array_creation,\n\t\t\t\t$.unary_expression,\n\t\t\t\t$.receive_expression,\n\t\t\t\t$.binary_expression,\n\t\t\t\t$.is_expression,\n\t\t\t\t$.in_expression,\n\t\t\t\t$.index_expression,\n\t\t\t\t$.slice_expression,\n\t\t\t\t$.as_type_cast_expression,\n\t\t\t\t$.selector_expression,\n\t\t\t\t$.enum_fetch,\n\t\t\t\t$.inc_expression,\n\t\t\t\t$.dec_expression,\n\t\t\t\t$.or_block_expression,\n\t\t\t\t$.option_propagation_expression,\n\t\t\t\t$.result_propagation_expression,\n\t\t\t),\n\n\t\t_expression_with_blocks: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.type_initializer,\n\t\t\t\t$.anon_struct_value_expression,\n\t\t\t\t$.if_expression,\n\t\t\t\t$.match_expression,\n\t\t\t\t$.select_expression,\n\t\t\t\t$.sql_expression,\n\t\t\t\t$.lock_expression,\n\t\t\t\t$.unsafe_expression,\n\t\t\t\t$.compile_time_if_expression,\n\t\t\t\t$.map_init_expression,\n\t\t\t),\n\n\t\tstrictly_expression_list: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.strictly_expression_list,\n\t\t\t\tseq(\n\t\t\t\t\tchoice($._expression, $.mutable_expression),\n\t\t\t\t\t',',\n\t\t\t\t\tsep(choice($._expression, $.mutable_expression)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tinc_expression: ($) => seq($._expression, '++'),\n\n\t\tdec_expression: ($) => seq($._expression, '--'),\n\n\t\tor_block_expression: ($) => seq($._expression, $.or_block),\n\n\t\toption_propagation_expression: ($) => prec(PREC.match_arm_type, seq($._expression, '?')),\n\n\t\tresult_propagation_expression: ($) => prec(PREC.match_arm_type, seq($._expression, '!')),\n\n\t\tanon_struct_value_expression: ($) =>\n\t\t\tseq(\n\t\t\t\t'struct',\n\t\t\t\t'{',\n\t\t\t\tchoice(\n\t\t\t\t\tfield('element_list', $.element_list),\n\t\t\t\t\t// For short struct init syntax\n\t\t\t\t\tfield('short_element_list', $.short_element_list),\n\t\t\t\t),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\tgo_expression: ($) => prec.left(PREC.composite_literal, seq('go', $._expression)),\n\n\t\tspawn_expression: ($) => prec.left(PREC.composite_literal, seq('spawn', $._expression)),\n\n\t\tparenthesized_expression: ($) => seq('(', field('expression', $._expression), ')'),\n\n\t\tcall_expression: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.primary,\n\t\t\t\tchoice(\n\t\t\t\t\tseq(field('function', token('json.decode')), field('arguments', $.special_argument_list)),\n\t\t\t\t\tseq(\n\t\t\t\t\t\tfield('name', $._expression),\n\t\t\t\t\t\toptional(field('type_parameters', $.type_parameters)),\n\t\t\t\t\t\tfield('arguments', $.argument_list),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\ttype_parameters: ($) => prec.dynamic(2, seq(token.immediate('['), sep($.plain_type), ']')),\n\n\t\targument_list: ($) =>\n\t\t\tseq('(', choice(repeat(seq($.argument, optional(list_separator))), $.short_lambda), ')'),\n\n\t\tshort_lambda: ($) =>\n\t\t\tseq('|', optional(sep($.reference_expression)), '|', $._expression_without_blocks),\n\n\t\targument: ($) =>\n\t\t\tchoice($._expression, $.mutable_expression, $.keyed_element, $.spread_expression),\n\n\t\tspecial_argument_list: ($) =>\n\t\t\tseq(\n\t\t\t\t'(',\n\t\t\t\talias($._plain_type_without_special, $.plain_type),\n\t\t\t\toptional(seq(',', $._expression)),\n\t\t\t\t')',\n\t\t\t),\n\n\t\ttype_initializer: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.type_initializer,\n\t\t\t\tseq(field('type', $.plain_type), field('body', $.type_initializer_body)),\n\t\t\t),\n\n\t\ttype_initializer_body: ($) =>\n\t\t\tseq(\n\t\t\t\t'{',\n\t\t\t\toptional(\n\t\t\t\t\tchoice(\n\t\t\t\t\t\tfield('element_list', $.element_list),\n\t\t\t\t\t\t// For short struct init syntax\n\t\t\t\t\t\tfield('short_element_list', $.short_element_list),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\telement_list: ($) =>\n\t\t\trepeat1(\n\t\t\t\tseq(\n\t\t\t\t\tchoice($.spread_expression, $.keyed_element, $.reference_expression),\n\t\t\t\t\toptional(list_separator),\n\t\t\t\t),\n\t\t\t),\n\n\t\tshort_element_list: ($) =>\n\t\t\trepeat1(seq(alias($._expression, $.element), optional(list_separator))),\n\n\t\tfield_name: ($) => $.reference_expression,\n\n\t\tkeyed_element: ($) => seq(field('key', $.field_name), ':', field('value', $._expression)),\n\n\t\tfunction_literal: ($) =>\n\t\t\tprec.right(\n\t\t\t\tseq(\n\t\t\t\t\t'fn',\n\t\t\t\t\toptional(field('capture_list', $.capture_list)),\n\t\t\t\t\toptional(field('generic_parameters', $.generic_parameters)),\n\t\t\t\t\tfield('signature', $.signature),\n\t\t\t\t\tfield('body', $.block),\n\t\t\t\t),\n\t\t\t),\n\n\t\tcapture_list: ($) => seq('[', sep($.capture), optional(','), ']'),\n\n\t\tcapture: ($) => seq(optional($.mutability_modifiers), $.reference_expression),\n\n\t\treference_expression: ($) => prec.left($.identifier),\n\t\ttype_reference_expression: ($) => prec.left($.identifier),\n\n\t\tunary_expression: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.unary,\n\t\t\t\tseq(field('operator', choice(...unary_operators)), field('operand', $._expression)),\n\t\t\t),\n\n\t\treceive_expression: ($) =>\n\t\t\tprec.right(PREC.unary, seq(field('operator', '<-'), field('operand', $._expression))),\n\n\t\tbinary_expression: ($) => {\n\t\t\tconst table = [\n\t\t\t\t[PREC.multiplicative, choice(...multiplicative_operators)],\n\t\t\t\t[PREC.additive, choice(...additive_operators)],\n\t\t\t\t[PREC.comparative, choice(...comparative_operators)],\n\t\t\t\t[PREC.and, '&&'],\n\t\t\t\t[PREC.or, '||'],\n\t\t\t];\n\n\t\t\treturn choice(\n\t\t\t\t...table.map(([precedence, operator]) =>\n\t\t\t\t\tprec.left(\n\t\t\t\t\t\tNumber(precedence),\n\t\t\t\t\t\tseq(\n\t\t\t\t\t\t\tfield('left', $._expression),\n\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\tfield('operator', operator),\n\t\t\t\t\t\t\tfield('right', $._expression),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t},\n\n\t\tas_type_cast_expression: ($) => seq($._expression, 'as', $.plain_type),\n\n\t\tor_block: ($) => seq('or', field('block', $.block)),\n\n\t\t_max_group: ($) => prec.left(PREC.resolve, choice($.pseudo_compile_time_identifier, $.literal)),\n\n\t\tescape_sequence: () =>\n\t\t\ttoken(\n\t\t\t\tprec(\n\t\t\t\t\t1,\n\t\t\t\t\tseq(\n\t\t\t\t\t\t'\\\\',\n\t\t\t\t\t\tchoice(\n\t\t\t\t\t\t\t/u[a-fA-F\\d]{4}/,\n\t\t\t\t\t\t\t/U[a-fA-F\\d]{8}/,\n\t\t\t\t\t\t\t/x[a-fA-F\\d]{2}/,\n\t\t\t\t\t\t\t/\\d{3}/,\n\t\t\t\t\t\t\t/\\r?\\n/,\n\t\t\t\t\t\t\t/['\"abfrntv$\\\\]/,\n\t\t\t\t\t\t\t/\\S/,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\tliteral: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.int_literal,\n\t\t\t\t$.float_literal,\n\t\t\t\t$._string_literal,\n\t\t\t\t$.rune_literal,\n\t\t\t\t$.none,\n\t\t\t\t$.true,\n\t\t\t\t$.false,\n\t\t\t\t$.nil,\n\t\t\t),\n\n\t\tnone: () => 'none',\n\t\ttrue: () => 'true',\n\t\tfalse: () => 'false',\n\t\tnil: () => 'nil',\n\n\t\tspread_expression: ($) => prec.right(PREC.unary, seq('...', $._expression)),\n\n\t\tmap_init_expression: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.composite_literal,\n\t\t\t\tseq('{', repeat(seq($.map_keyed_element, optional(list_separator))), '}'),\n\t\t\t),\n\n\t\tmap_keyed_element: ($) => seq(field('key', $._expression), ':', field('value', $._expression)),\n\n\t\tarray_creation: ($) => prec.right(PREC.multiplicative, $._array),\n\n\t\tfixed_array_creation: ($) => prec.right(PREC.multiplicative, seq($._array, '!')),\n\n\t\t_array: ($) => seq('[', repeat(seq($._expression, optional(','))), ']'),\n\n\t\tselector_expression: ($) =>\n\t\t\tprec.dynamic(\n\t\t\t\t-1,\n\t\t\t\tprec(\n\t\t\t\t\tPREC.primary,\n\t\t\t\t\tseq(\n\t\t\t\t\t\tfield('operand', $._expression),\n\t\t\t\t\t\tchoice('.', '?.'),\n\t\t\t\t\t\tfield('field', choice($.reference_expression, $.compile_time_selector_expression)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\tcompile_time_selector_expression: ($) =>\n\t\t\tseq(\n\t\t\t\ttoken.immediate('$('),\n\t\t\t\tfield('field', choice($.reference_expression, $.selector_expression)),\n\t\t\t\t')',\n\t\t\t),\n\n\t\tindex_expression: ($) =>\n\t\t\tprec.dynamic(\n\t\t\t\t-1,\n\t\t\t\tprec.right(\n\t\t\t\t\tPREC.primary,\n\t\t\t\t\tseq(\n\t\t\t\t\t\tfield('operand', $._expression),\n\t\t\t\t\t\tchoice('[', token.immediate('['), token('#[')),\n\t\t\t\t\t\tfield('index', $._expression),\n\t\t\t\t\t\t']',\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\tslice_expression: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.primary,\n\t\t\t\tseq(\n\t\t\t\t\tfield('operand', $._expression),\n\t\t\t\t\tchoice('[', token.immediate('['), token('#[')),\n\t\t\t\t\t$.range,\n\t\t\t\t\t']',\n\t\t\t\t),\n\t\t\t),\n\n\t\tif_expression: ($) =>\n\t\t\tseq(\n\t\t\t\t'if',\n\t\t\t\tchoice(field('condition', $._expression), field('guard', $.var_declaration)),\n\t\t\t\tfield('block', $.block),\n\t\t\t\toptional($.else_branch),\n\t\t\t),\n\n\t\telse_branch: ($) =>\n\t\t\tseq('else', field('else_branch', choice(field('block', $.block), $.if_expression))),\n\n\t\tcompile_time_if_expression: ($) =>\n\t\t\tseq(\n\t\t\t\t'$if',\n\t\t\t\tfield('condition', seq($._expression, optional('?'))),\n\t\t\t\tfield('block', $.block),\n\t\t\t\toptional(seq('$else', field('else_branch', choice($.block, $.compile_time_if_expression)))),\n\t\t\t),\n\n\t\tis_expression: ($) =>\n\t\t\tprec.dynamic(\n\t\t\t\t2,\n\t\t\t\tseq(\n\t\t\t\t\tfield('left', seq(optional($.mutability_modifiers), $._expression)),\n\t\t\t\t\tchoice('is', '!is'),\n\t\t\t\t\tfield('right', $.plain_type),\n\t\t\t\t),\n\t\t\t),\n\n\t\tin_expression: ($) =>\n\t\t\tprec.left(\n\t\t\t\tPREC.comparative,\n\t\t\t\tseq(field('left', $._expression), choice('in', '!in'), field('right', $._expression)),\n\t\t\t),\n\n\t\tenum_fetch: ($) => prec.dynamic(-1, seq('.', $.reference_expression)),\n\n\t\tmatch_expression: ($) =>\n\t\t\tseq(\n\t\t\t\t'match',\n\t\t\t\tfield('condition', choice($._expression, $.mutable_expression)),\n\t\t\t\t'{',\n\t\t\t\toptional($.match_arms),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\tmatch_arms: ($) => repeat1(choice($.match_arm, $.match_else_arm_clause)),\n\n\t\tmatch_arm: ($) => seq(field('value', $.match_expression_list), field('block', $.block)),\n\n\t\tmatch_expression_list: ($) =>\n\t\t\tsep(\n\t\t\t\tchoice($._expression_without_blocks, $.match_arm_type, alias($._definite_range, $.range)),\n\t\t\t),\n\n\t\tmatch_arm_type: ($) => $.plain_type,\n\n\t\tmatch_else_arm_clause: ($) => seq('else', field('block', $.block)),\n\n\t\tselect_expression: ($) =>\n\t\t\tseq(\n\t\t\t\t'select',\n\t\t\t\toptional(field('selected_variables', $.expression_list)),\n\t\t\t\t'{',\n\t\t\t\trepeat($.select_arm),\n\t\t\t\toptional($.select_else_arn_clause),\n\t\t\t\t'}',\n\t\t\t),\n\n\t\tselect_arm: ($) => seq($.select_arm_statement, $.block),\n\n\t\tselect_arm_statement: ($) =>\n\t\t\tprec.left(\n\t\t\t\tchoice(\n\t\t\t\t\talias($.select_var_declaration, $.var_declaration),\n\t\t\t\t\t$.send_statement,\n\t\t\t\t\tseq(\n\t\t\t\t\t\talias($.expression_without_blocks_list, $.expression_list),\n\t\t\t\t\t\toptional($._select_arm_assignment_statement),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\t_select_arm_assignment_statement: ($) =>\n\t\t\tseq(\n\t\t\t\tchoice(...assignment_operators),\n\t\t\t\talias($.expression_without_blocks_list, $.expression_list),\n\t\t\t),\n\n\t\tselect_var_declaration: ($) =>\n\t\t\tprec.left(\n\t\t\t\tseq(\n\t\t\t\t\tfield('var_list', $.identifier_list),\n\t\t\t\t\t':=',\n\t\t\t\t\tfield('expression_list', alias($.expression_without_blocks_list, $.expression_list)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tselect_else_arn_clause: ($) => seq('else', $.block),\n\n\t\tlock_expression: ($) =>\n\t\t\tseq(\n\t\t\t\tchoice('lock', 'rlock'),\n\t\t\t\toptional(field('locked_variables', $.expression_list)),\n\t\t\t\tfield('body', $.block),\n\t\t\t),\n\n\t\tunsafe_expression: ($) => seq('unsafe', $.block),\n\n\t\t// TODO: this should be put into a separate grammar to avoid any \"noise\"\n\t\tsql_expression: ($) => prec(PREC.resolve, seq('sql', optional($.identifier), $._content_block)),\n\n\t\t// ==================== LITERALS ====================\n\n\t\tint_literal: () => token(int_literal),\n\n\t\tfloat_literal: () => token(float_literal),\n\n\t\trune_literal: () =>\n\t\t\ttoken(\n\t\t\t\tseq(\n\t\t\t\t\t'`',\n\t\t\t\t\tchoice(\n\t\t\t\t\t\t/[^'\\\\]/,\n\t\t\t\t\t\t\"'\",\n\t\t\t\t\t\t'\"',\n\t\t\t\t\t\tseq(\n\t\t\t\t\t\t\t'\\\\',\n\t\t\t\t\t\t\tchoice(\n\t\t\t\t\t\t\t\t'0',\n\t\t\t\t\t\t\t\t'`',\n\t\t\t\t\t\t\t\tseq('x', hex_digit, hex_digit),\n\t\t\t\t\t\t\t\tseq(octal_digit, octal_digit, octal_digit),\n\t\t\t\t\t\t\t\tseq('u', hex_digit, hex_digit, hex_digit, hex_digit),\n\t\t\t\t\t\t\t\tseq(\n\t\t\t\t\t\t\t\t\t'U',\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t\thex_digit,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tseq(choice('a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\\\', \"'\", '\"')),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\t'`',\n\t\t\t\t),\n\t\t\t),\n\n\t\t_string_literal: ($) =>\n\t\t\tchoice($.interpreted_string_literal, $.c_string_literal, $.raw_string_literal),\n\n\t\tinterpreted_string_literal: ($) =>\n\t\t\tchoice(\n\t\t\t\tseq(\"'\", repeat(stringBody(/[^'\\\\$]+/, $)), \"'\"),\n\t\t\t\tseq('\"', repeat(stringBody(/[^\"\\\\$]+/, $)), '\"'),\n\t\t\t),\n\n\t\tc_string_literal: ($) =>\n\t\t\tchoice(\n\t\t\t\tseq(\"c'\", repeat(stringBody(/[^'\\\\$]+/, $)), \"'\"),\n\t\t\t\tseq('c\"', repeat(stringBody(/[^\"\\\\$]+/, $)), '\"'),\n\t\t\t),\n\n\t\traw_string_literal: (_) =>\n\t\t\tchoice(\n\t\t\t\tseq(\"r'\", repeat(token.immediate(prec.right(1, /[^']+/))), \"'\"),\n\t\t\t\tseq('r\"', repeat(token.immediate(prec.right(1, /[^\"]+/))), '\"'),\n\t\t\t),\n\n\t\tstring_interpolation: ($) =>\n\t\t\tseq(\n\t\t\t\talias('${', $.interpolation_opening),\n\t\t\t\tchoice(\n\t\t\t\t\trepeat(alias($._expression, $.interpolation_expression)),\n\t\t\t\t\tseq(alias($._expression, $.interpolation_expression), $.format_specifier),\n\t\t\t\t),\n\t\t\t\talias('}', $.interpolation_closing),\n\t\t\t),\n\n\t\tformat_specifier: ($) =>\n\t\t\tseq(\n\t\t\t\ttoken(':'),\n\t\t\t\tchoice(\n\t\t\t\t\tformat_flag,\n\t\t\t\t\tseq(\n\t\t\t\t\t\toptional(choice(token(/[+\\-]/), token('0'))),\n\t\t\t\t\t\toptional($.int_literal),\n\t\t\t\t\t\toptional(seq('.', $.int_literal)),\n\t\t\t\t\t\toptional(format_flag),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\n\t\tpseudo_compile_time_identifier: ($) =>\n\t\t\ttoken(seq('@', alias(token.immediate(/[A-Z][A-Z0-9_]+/), $.identifier))),\n\n\t\tidentifier: () =>\n\t\t\ttoken(\n\t\t\t\tseq(\n\t\t\t\t\toptional('@'),\n\t\t\t\t\toptional('$'),\n\t\t\t\t\toptional('C.'),\n\t\t\t\t\toptional('JS.'),\n\t\t\t\t\tchoice(unicode_letter, '_'),\n\t\t\t\t\trepeat(choice(letter, unicode_digit)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tvisibility_modifiers: () => prec.left(choice('pub', '__global')),\n\n\t\tmutability_modifiers: () =>\n\t\t\tprec.left(\n\t\t\t\tPREC.resolve,\n\t\t\t\tchoice(seq('mut', optional('static'), optional('volatile')), 'shared'),\n\t\t\t),\n\n\t\tmutable_identifier: ($) => prec(PREC.resolve, seq($.mutability_modifiers, $.identifier)),\n\n\t\tmutable_expression: ($) => prec(PREC.resolve, seq($.mutability_modifiers, $._expression)),\n\n\t\tidentifier_list: ($) => prec(PREC.and, sep(choice($.mutable_identifier, $.identifier))),\n\n\t\texpression_list: ($) => prec(PREC.resolve, sep(choice($._expression, $.mutable_expression))),\n\n\t\texpression_without_blocks_list: ($) => prec(PREC.resolve, sep($._expression_without_blocks)),\n\n\t\t// ==================== TYPES ====================\n\n\t\t// int | string | Foo\n\t\tsum_type: ($) =>\n\t\t\tprec.right(\n\t\t\t\tseq($.plain_type, repeat1(seq(optional(/\\s+/), token.immediate('|'), $.plain_type))),\n\t\t\t),\n\n\t\tplain_type: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.primary,\n\t\t\t\tchoice($._plain_type_without_special, $.option_type, $.result_type, $.multi_return_type),\n\t\t\t),\n\n\t\t_plain_type_without_special: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.primary,\n\t\t\t\tchoice(\n\t\t\t\t\t$.type_reference_expression,\n\t\t\t\t\t$.qualified_type,\n\t\t\t\t\t$.pointer_type,\n\t\t\t\t\t$.wrong_pointer_type,\n\t\t\t\t\t$.array_type,\n\t\t\t\t\t$.fixed_array_type,\n\t\t\t\t\t$.function_type,\n\t\t\t\t\t$.generic_type,\n\t\t\t\t\t$.map_type,\n\t\t\t\t\t$.channel_type,\n\t\t\t\t\t$.shared_type,\n\t\t\t\t\t$.thread_type,\n\t\t\t\t\t$.atomic_type,\n\t\t\t\t\t$.anon_struct_type,\n\t\t\t\t),\n\t\t\t),\n\n\t\tanon_struct_type: ($) => seq('struct', $._struct_body),\n\n\t\tmulti_return_type: ($) => seq('(', sep($.plain_type), optional(','), ')'),\n\n\t\tresult_type: ($) => prec.right(seq('!', optional($.plain_type))),\n\n\t\toption_type: ($) => prec.right(seq('?', optional($.plain_type))),\n\n\t\tqualified_type: ($) =>\n\t\t\tseq(field('module', $.reference_expression), '.', field('name', $.type_reference_expression)),\n\n\t\tfixed_array_type: ($) =>\n\t\t\tseq(\n\t\t\t\t'[',\n\t\t\t\tfield('size', choice($.int_literal, $.reference_expression, $.selector_expression)),\n\t\t\t\t']',\n\t\t\t\tfield('element', $.plain_type),\n\t\t\t),\n\n\t\tarray_type: ($) => prec.right(PREC.primary, seq('[', ']', field('element', $.plain_type))),\n\n\t\tpointer_type: ($) => prec(PREC.match_arm_type, seq('&', $.plain_type)),\n\n\t\t// In languages like Go, pointers use an asterisk, not an ampersand,\n\t\t// so this rule is needed to properly parse and then give an error to the user.\n\t\twrong_pointer_type: ($) => prec(PREC.match_arm_type, seq('*', $.plain_type)),\n\n\t\tmap_type: ($) => seq('map[', field('key', $.plain_type), ']', field('value', $.plain_type)),\n\n\t\tchannel_type: ($) => prec.right(PREC.primary, seq('chan', $.plain_type)),\n\n\t\tshared_type: ($) => seq('shared', $.plain_type),\n\n\t\tthread_type: ($) => seq('thread', $.plain_type),\n\n\t\tatomic_type: ($) => seq('atomic', $.plain_type),\n\n\t\tgeneric_type: ($) =>\n\t\t\tseq(choice($.qualified_type, $.type_reference_expression), $.type_parameters),\n\n\t\tfunction_type: ($) => prec.right(seq('fn', field('signature', $.signature))),\n\n\t\t// ==================== TYPES END ====================\n\n\t\t// ==================== STATEMENTS ====================\n\n\t\t_statement: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.simple_statement,\n\t\t\t\t$.assert_statement,\n\t\t\t\t$.continue_statement,\n\t\t\t\t$.break_statement,\n\t\t\t\t$.return_statement,\n\t\t\t\t$.asm_statement,\n\t\t\t\t$.goto_statement,\n\t\t\t\t$.labeled_statement,\n\t\t\t\t$.defer_statement,\n\t\t\t\t$.for_statement,\n\t\t\t\t$.compile_time_for_statement,\n\t\t\t\t$.send_statement,\n\t\t\t\t$.block,\n\t\t\t\t$.hash_statement,\n\t\t\t\t$.append_statement,\n\t\t\t),\n\n\t\tsimple_statement: ($) =>\n\t\t\tchoice(\n\t\t\t\t$.var_declaration,\n\t\t\t\t$._expression,\n\t\t\t\t$.assignment_statement,\n\t\t\t\talias($.strictly_expression_list, $.expression_list),\n\t\t\t),\n\n\t\tassert_statement: ($) =>\n\t\t\tprec.left(seq('assert', $._expression, optional(seq(',', $._expression)))),\n\n\t\tappend_statement: ($) =>\n\t\t\tprec(PREC.unary, seq(field('left', $._expression), '<<', field('right', $._expression))),\n\n\t\tsend_statement: ($) =>\n\t\t\tprec.right(\n\t\t\t\tPREC.primary,\n\t\t\t\tseq(field('channel', $._expression), '<-', field('value', $._expression)),\n\t\t\t),\n\n\t\tvar_declaration: ($) =>\n\t\t\tprec.right(\n\t\t\t\tseq(\n\t\t\t\t\tfield('var_list', $.expression_list),\n\t\t\t\t\t':=',\n\t\t\t\t\tfield('expression_list', $.expression_list),\n\t\t\t\t),\n\t\t\t),\n\n\t\tvar_definition_list: ($) => sep($.var_definition),\n\n\t\tvar_definition: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.type_initializer,\n\t\t\t\tseq(optional(field('modifiers', 'mut')), field('name', $.identifier)),\n\t\t\t),\n\n\t\tassignment_statement: ($) =>\n\t\t\tseq(\n\t\t\t\tfield('left', $.expression_list),\n\t\t\t\tfield('operator', choice(...assignment_operators)),\n\t\t\t\tfield('right', $.expression_list),\n\t\t\t),\n\n\t\t_block_element: ($) =>\n    \t\tchoice(\n    \t\t    $._statement,\n    \t\t    $.import_list,\n    \t\t    $._top_level_declaration\n    \t\t),\n\n\t\tblock: ($) => seq('{', repeat(seq($._block_element, optional(semi))), '}'),\n\n\t\tdefer_statement: ($) => seq('defer', $.block),\n\n\t\tlabel_reference: ($) => $.identifier,\n\n\t\tgoto_statement: ($) => seq('goto', $.label_reference),\n\n\t\tbreak_statement: ($) => prec.right(seq('break', optional($.label_reference))),\n\n\t\tcontinue_statement: ($) => prec.right(seq('continue', optional($.label_reference))),\n\n\t\treturn_statement: ($) =>\n\t\t\tprec.right(seq('return', optional(field('expression_list', $.expression_list)))),\n\n\t\tlabel_definition: ($) => seq($.identifier, ':'),\n\n\t\tlabeled_statement: ($) => prec.right(seq($.label_definition, optional($._statement))),\n\n\t\tcompile_time_for_statement: ($) => seq('$for', $.range_clause, field('body', $.block)),\n\n\t\tfor_statement: ($) =>\n\t\t\tseq(\n\t\t\t\t'for',\n\t\t\t\toptional(choice($.range_clause, $.for_clause, $.is_clause, $._expression)),\n\t\t\t\tfield('body', $.block),\n\t\t\t),\n\n\t\tis_clause: ($) =>\n\t\t\tprec(PREC.primary, seq(optional(alias('mut', $.mutability_modifiers)), $.is_expression)),\n\n\t\trange_clause: ($) =>\n\t\t\tprec.left(\n\t\t\t\tPREC.primary,\n\t\t\t\tseq(\n\t\t\t\t\tfield('left', $.var_definition_list),\n\t\t\t\t\t'in',\n\t\t\t\t\tfield('right', choice(alias($._definite_range, $.range), $._expression)),\n\t\t\t\t),\n\t\t\t),\n\n\t\tfor_clause: ($) =>\n\t\t\tprec.left(\n\t\t\t\tseq(\n\t\t\t\t\toptional(field('initializer', $.simple_statement)),\n\t\t\t\t\t';',\n\t\t\t\t\toptional(field('condition', $._expression)),\n\t\t\t\t\t';',\n\t\t\t\t\toptional(field('update', $.simple_statement)),\n\t\t\t\t),\n\t\t\t),\n\n\t\t_definite_range: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.multiplicative,\n\t\t\t\tseq(\n\t\t\t\t\tfield('start', $._expression),\n\t\t\t\t\tfield('operator', choice('..', '...')),\n\t\t\t\t\tfield('end', $._expression),\n\t\t\t\t),\n\t\t\t),\n\n\t\trange: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.multiplicative,\n\t\t\t\tseq(\n\t\t\t\t\toptional(field('start', $._expression)),\n\t\t\t\t\tfield('operator', '..'),\n\t\t\t\t\toptional(field('end', $._expression)),\n\t\t\t\t),\n\t\t\t),\n\n\t\thash_statement: () => seq('#', token.immediate(repeat1(/[^\\\\\\r\\n]/))),\n\n\t\tasm_statement: ($) => \n            seq(\n                'asm',\n\t\t\t\toptional(field('modifiers', choice('volatile', 'goto'))),\n                optional(field('arch', $.identifier)),\n                $._content_block\n            ),\n\n\t\t// Loose checking for asm and sql statements\n\t\t_content_block: () => seq('{', token.immediate(prec(1, /[^{}]+/)), '}'),\n\n\t\t// ==================== ATTRIBUTES ====================\n\n\t\tattributes: ($) => repeat1(seq($.attribute, optional(terminator))),\n\n\t\tattribute: ($) =>\n\t\t\tseq(\n\t\t\t\tchoice('[', '@['),\n\t\t\t\tseq($.attribute_expression, repeat(seq(';', $.attribute_expression))),\n\t\t\t\t']',\n\t\t\t),\n\n\t\tattribute_expression: ($) => prec(PREC.attributes, choice($.if_attribute, $._plain_attribute)),\n\n\t\t// [if some ?]\n\t\t// @[if some ?]\n\t\tif_attribute: ($) => prec(PREC.attributes, seq('if', $.reference_expression, optional('?'))),\n\n\t\t_plain_attribute: ($) => choice($.literal_attribute, $.value_attribute, $.key_value_attribute),\n\n\t\t// ['/query']\n\t\t// @['/query']\n\t\tliteral_attribute: ($) => prec(PREC.attributes, $.literal),\n\n\t\tvalue_attribute: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.attributes,\n\t\t\t\tfield('name', choice(alias('unsafe', $.reference_expression), $.reference_expression)),\n\t\t\t),\n\n\t\t// [key]\n\t\t// [key: value]\n\t\t// @[key]\n\t\t// @[key: value]\n\t\tkey_value_attribute: ($) =>\n\t\t\tprec(\n\t\t\t\tPREC.attributes,\n\t\t\t\tseq($.value_attribute, ':', field('value', choice($.literal, $.identifier))),\n\t\t\t),\n\t},\n});\n\n/**\n * Creates a comma separated rule sequence to match one or more of the passed rule.\n *\n * @param {RuleOrLiteral} rule\n *\n * @return {SeqRule}\n *\n */\nfunction sep(rule) {\n\treturn seq(rule, repeat(seq(',', rule)));\n}\n\n/**\n *\n * @param {RegExp} re\n * @param {$} $\n *\n * @return {SeqRule}\n *\n */\nfunction stringBody(re, $) {\n\treturn choice(token.immediate(prec.right(1, re)), '$', $.escape_sequence, $.string_interpolation);\n}\n\n/**\n * @param {...string} args - One or more regular expression patterns.\n *\n * @return {PatternRule}\n */\nfunction regexOr(...args) {\n\tconst regex = args.length > 1 ? args.join('|') : args[0];\n\treturn {\n\t\ttype: 'PATTERN',\n\t\tvalue: regex,\n\t};\n}\n"
  },
  {
    "path": "tree_sitter_v/package.json",
    "content": "{\n  \"name\": \"tree-sitter-v\",\n  \"version\": \"0.0.6\",\n  \"private\": true,\n  \"description\": \"V grammar for tree-sitter\",\n  \"main\": \"bindings/node\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"test\": \"tree-sitter test\",\n    \"generate\": \"tree-sitter generate && v bindings/generate_types.vsh\",\n    \"parse\": \"tree-sitter parse\",\n    \"format\": \"prettier --write grammar.js\"\n  },\n  \"devDependencies\": {\n    \"prettier\": \"^3.7.4\",\n    \"tree-sitter-cli\": \"0.26.3\"\n  }\n}\n"
  },
  {
    "path": "tree_sitter_v/queries/helix.highlights.scm",
    "content": "[\n (line_comment)\n (block_comment)\n (shebang)\n] @comment\n\n(module_clause\n (identifier) @namespace)\n\n(import_path\n (import_name) @namespace)\n\n(import_alias\n (import_name) @namespace)\n\n(enum_fetch\n (reference_expression) @constant)\n\n(enum_field_definition\n (identifier) @constant)\n\n(global_var_definition\n (identifier) @constant)\n\n(compile_time_if_expression\n condition: (reference_expression) @constant)\n\n(compile_time_if_expression\n condition: (binary_expression\n              left: (reference_expression) @constant\n              right: (reference_expression) @constant))\n\n(compile_time_if_expression\n condition: (binary_expression\n              left: (reference_expression) @constant\n              right: (unary_expression (reference_expression) @constant)))\n\n(label_reference) @label\n\n(parameter_declaration\n name: (identifier) @variable.parameter)\n(receiver\n name: (identifier) @variable.parameter)\n(function_declaration\n name: (identifier) @function)\n(function_declaration\n receiver: (receiver)\n name: (identifier) @function.method)\n(interface_method_definition\n name: (identifier) @function.method)\n\n(short_lambda\n  (reference_expression) @parameter)\n(call_expression\n  name: (selector_expression\n  field: (reference_expression) @function.method))\n\n(call_expression\n name: (reference_expression) @function)\n\n(struct_declaration\n name: (identifier) @type)\n\n(enum_declaration\n name: (identifier) @type)\n\n(interface_declaration\n name: (identifier) @type)\n\n(type_declaration\n name: (identifier) @type)\n\n(struct_field_declaration\n name: (identifier) @variable.other.member)\n\n(field_name) @variable.other.member\n\n(selector_expression\n field: (reference_expression) @variable.other.member)\n\n(int_literal) @constant.numeric.integer\n(escape_sequence) @constant.character.escape\n\n[\n (c_string_literal)\n (raw_string_literal)\n (interpreted_string_literal)\n (string_interpolation)\n (rune_literal)\n] @string\n\n(string_interpolation\n (interpolation_opening) @punctuation.bracket\n (interpolation_expression) @none\n (interpolation_closing) @punctuation.bracket)\n\n(attribute) @attribute\n\n[\n (type_reference_expression)\n ] @type\n\n[\n (true)\n (false)\n] @constant.builtin.boolean\n\n[\n  \"pub\"\n  \"assert\"\n  \"asm\"\n  \"defer\"\n  \"unsafe\"\n  \"sql\"\n  (nil)\n  (none)\n] @keyword\n\n[\n  \"interface\"\n  \"enum\"\n  \"type\"\n  \"union\"\n  \"struct\"\n  \"module\"\n] @keyword.storage.type\n\n[\n  \"static\"\n  \"const\"\n  \"__global\"\n] @keyword.storage.modifier\n\n[\n  \"mut\"\n] @keyword.storage.modifier.mut\n\n[\n  \"shared\"\n  \"lock\"\n  \"rlock\"\n  \"spawn\"\n  \"break\"\n  \"continue\"\n  \"go\"\n] @keyword.control\n\n[\n  \"if\"\n  \"$if\"\n  \"select\"\n  \"else\"\n  \"$else\"\n  \"match\"\n] @keyword.control.conditional\n\n[\n  \"for\"\n] @keyword.control.repeat\n\n[\n  \"goto\"\n  \"return\"\n] @keyword.control.return\n\n[\n  \"fn\"\n] @keyword.control.function\n\n\n[\n  \"import\"\n] @keyword.control.import\n\n[\n  \"as\"\n  \"in\"\n  \"is\"\n  \"or\"\n] @keyword.operator\n\n[\n \".\"\n \",\"\n \":\"\n \";\"\n] @punctuation.delimiter\n\n[\n \"(\"\n \")\"\n \"{\"\n \"}\"\n \"[\"\n \"]\"\n] @punctuation.bracket\n\n(array_creation) @punctuation.bracket\n\n[\n \"++\"\n \"--\"\n\n \"+\"\n \"-\"\n \"*\"\n \"/\"\n \"%\"\n\n \"~\"\n \"&\"\n \"|\"\n \"^\"\n\n \"!\"\n \"&&\"\n \"||\"\n \"!=\"\n\n \"<<\"\n \">>\"\n\n \"<\"\n \">\"\n \"<=\"\n \">=\"\n\n \"+=\"\n \"-=\"\n \"*=\"\n \"/=\"\n \"&=\"\n \"|=\"\n \"^=\"\n \"<<=\"\n \">>=\"\n\n \"=\"\n \":=\"\n \"==\"\n\n \"?\"\n \"<-\"\n \"$\"\n \"..\"\n \"...\"\n] @operator\n"
  },
  {
    "path": "tree_sitter_v/queries/highlights.scm",
    "content": "(ERROR) @error\n\n[\n (line_comment)\n (block_comment)\n (shebang)\n] @comment\n\n(identifier) @variable\n(import_path) @variable\n\n(parameter_declaration\n  name: (identifier) @parameter)\n(function_declaration\n  name: (identifier) @function)\n(function_declaration\n  receiver: (receiver)\n  name: (identifier) @method)\n\n(short_lambda\n  (reference_expression) @parameter)\n(call_expression\n  name: (selector_expression\n    field: (reference_expression) @method))\n\n(type_reference_expression) @type\n(pointer_type) @type\n(array_type) @type\n\n(field_name) @property\n(selector_expression\n  field: (reference_expression) @property)\n\n(int_literal) @number\n(interpreted_string_literal) @string\n(rune_literal) @string\n(escape_sequence) @string.escape\n\n[\n \"as\"\n \"asm\"\n \"assert\"\n ;\"atomic\"\n \"break\"\n \"const\"\n \"continue\"\n \"defer\"\n \"else\"\n \"enum\"\n \"fn\"\n \"for\"\n \"$for\"\n \"go\"\n \"goto\"\n \"if\"\n \"$if\"\n \"implements\"\n \"import\"\n \"in\"\n \"!in\"\n \"interface\"\n \"is\"\n \"!is\"\n \"lock\"\n \"match\"\n \"module\"\n \"mut\"\n \"or\"\n \"pub\"\n \"return\"\n \"rlock\"\n \"select\"\n \"shared\"\n \"spawn\"\n \"static\"\n \"struct\"\n \"type\"\n \"union\"\n \"unsafe\"\n] @keyword\n\n[\n (true)\n (false)\n] @boolean\n\n[\n \".\"\n \",\"\n \":\"\n \";\"\n] @punctuation.delimiter\n\n[\n \"(\"\n \")\"\n \"{\"\n \"}\"\n \"[\"\n \"]\"\n] @punctuation.bracket\n\n(array_creation) @punctuation.bracket\n\n[\n \"++\"\n \"--\"\n\n \"+\"\n \"-\"\n \"*\"\n \"/\"\n \"%\"\n\n \"~\"\n \"&\"\n \"|\"\n \"^\"\n\n \"!\"\n \"&&\"\n \"||\"\n \"!=\"\n\n \"<<\"\n \">>\"\n\n \"<\"\n \">\"\n \"<=\"\n \">=\"\n\n \"+=\"\n \"-=\"\n \"*=\"\n \"/=\"\n \"&=\"\n \"|=\"\n \"^=\"\n \"<<=\"\n \">>=\"\n\n \"=\"\n \":=\"\n \"==\"\n\n \"?\"\n \"<-\"\n \"$\"\n \"..\"\n \"...\"\n] @operator\n"
  },
  {
    "path": "tree_sitter_v/src/grammar.json",
    "content": "{\n  \"$schema\": \"https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json\",\n  \"name\": \"v\",\n  \"word\": \"identifier\",\n  \"rules\": {\n    \"source_file\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"shebang\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"module_clause\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"import_list\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_top_level_declaration\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_statement\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"shebang\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"#!\"\n        },\n        {\n          \"type\": \"PATTERN\",\n          \"value\": \".*\"\n        }\n      ]\n    },\n    \"line_comment\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"//\"\n        },\n        {\n          \"type\": \"PATTERN\",\n          \"value\": \".*\"\n        }\n      ]\n    },\n    \"block_comment\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"/*\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"PATTERN\",\n                \"value\": \"\\\\*\"\n              },\n              {\n                \"type\": \"PATTERN\",\n                \"value\": \"[^*]|[/][^*]|[^*][/]\"\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"*/\"\n        }\n      ]\n    },\n    \"comment\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"line_comment\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block_comment\"\n        }\n      ]\n    },\n    \"module_clause\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"attributes\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"module\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"identifier\"\n        }\n      ]\n    },\n    \"import_list\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"REPEAT1\",\n        \"content\": {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_declaration\"\n        }\n      }\n    },\n    \"import_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"import\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_spec\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"\\n\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"\\r\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"\\r\\n\"\n                }\n              ]\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \";\"\n            }\n          ]\n        }\n      ]\n    },\n    \"import_spec\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_path\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"import_alias\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"selective_import_list\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        }\n      ]\n    },\n    \"import_path\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_name\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \".\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"import_name\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"import_name\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"identifier\"\n    },\n    \"import_alias\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"as\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_name\"\n        }\n      ]\n    },\n    \"selective_import_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"reference_expression\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\n\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\r\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\r\\n\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"reference_expression\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"_top_level_declaration\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"const_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"global_var_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"type_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"function_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"static_method_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"struct_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"enum_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"interface_declaration\"\n        }\n      ]\n    },\n    \"const_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attributes\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"visibility_modifiers\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"const\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"const_definition\"\n            },\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"(\"\n                },\n                {\n                  \"type\": \"REPEAT\",\n                  \"content\": {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"SYMBOL\",\n                        \"name\": \"const_definition\"\n                      },\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\n\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\r\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\r\\n\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \";\"\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \")\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"const_definition\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"=\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        }\n      ]\n    },\n    \"global_var_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attributes\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"__global\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"global_var_definition\"\n            },\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"(\"\n                },\n                {\n                  \"type\": \"REPEAT\",\n                  \"content\": {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"SYMBOL\",\n                        \"name\": \"global_var_definition\"\n                      },\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\n\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\r\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\r\\n\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \";\"\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \")\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"global_var_definition\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"modifiers\",\n              \"content\": {\n                \"type\": \"STRING\",\n                \"value\": \"volatile\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_global_var_value\"\n            }\n          ]\n        }\n      ]\n    },\n    \"_global_var_value\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"=\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        }\n      ]\n    },\n    \"type_declaration\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"visibility_modifiers\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"type\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"identifier\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"generic_parameters\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"generic_parameters\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"=\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"type\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"sum_type\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"plain_type\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"function_declaration\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"attributes\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"attributes\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"visibility_modifiers\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"fn\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"receiver\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"receiver\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_function_name\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"generic_parameters\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"generic_parameters\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"signature\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"signature\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"body\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"block\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"static_method_declaration\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"attributes\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"attributes\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"visibility_modifiers\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"fn\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"static_receiver\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"static_receiver\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \".\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_function_name\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"generic_parameters\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"generic_parameters\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"signature\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"signature\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"body\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"block\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"static_receiver\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"reference_expression\"\n    },\n    \"_function_name\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"identifier\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"overridable_operator\"\n        }\n      ]\n    },\n    \"overridable_operator\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"+\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"-\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"*\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"/\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"%\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"<\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \">\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"==\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"!=\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"<=\"\n          }\n        },\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \">=\"\n          }\n        }\n      ]\n    },\n    \"receiver\": {\n      \"type\": \"PREC\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"(\"\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"FIELD\",\n                    \"name\": \"mutability\",\n                    \"content\": {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"mutability_modifiers\"\n                    }\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"name\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"identifier\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"type\",\n                \"content\": {\n                  \"type\": \"ALIAS\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_plain_type_without_special\"\n                  },\n                  \"named\": true,\n                  \"value\": \"plain_type\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \")\"\n          }\n        ]\n      }\n    },\n    \"signature\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"parameters\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"parameter_list\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"type_parameter_list\"\n                }\n              ]\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"result\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"plain_type\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"parameter_list\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"(\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"variadic_parameter\"\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"SYMBOL\",\n                            \"name\": \"parameter_declaration\"\n                          },\n                          {\n                            \"type\": \"REPEAT\",\n                            \"content\": {\n                              \"type\": \"SEQ\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \",\"\n                                },\n                                {\n                                  \"type\": \"SYMBOL\",\n                                  \"name\": \"parameter_declaration\"\n                                }\n                              ]\n                            }\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"SEQ\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \",\"\n                              },\n                              {\n                                \"type\": \"SYMBOL\",\n                                \"name\": \"variadic_parameter\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"BLANK\"\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \")\"\n          }\n        ]\n      }\n    },\n    \"parameter_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"mutability\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutability_modifiers\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"variadic\",\n              \"content\": {\n                \"type\": \"STRING\",\n                \"value\": \"...\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"type\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        }\n      ]\n    },\n    \"variadic_parameter\": {\n      \"type\": \"STRING\",\n      \"value\": \"...\"\n    },\n    \"type_parameter_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"(\"\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"type_parameter_declaration\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"type_parameter_declaration\"\n                  }\n                ]\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"type_parameter_declaration\": {\n      \"type\": \"PREC\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutability_modifiers\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"variadic\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"...\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"type\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            }\n          }\n        ]\n      }\n    },\n    \"generic_parameters\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"IMMEDIATE_TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"[\"\n          }\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"generic_parameter\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"generic_parameter\"\n                  }\n                ]\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \",\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        }\n      ]\n    },\n    \"generic_parameter\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"identifier\"\n    },\n    \"struct_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attributes\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"visibility_modifiers\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"struct\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"union\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"generic_parameters\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"generic_parameters\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"implements\"\n                },\n                {\n                  \"type\": \"FIELD\",\n                  \"name\": \"implements\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"implements_clause\"\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_struct_body\"\n        }\n      ]\n    },\n    \"implements_clause\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"type_reference_expression\"\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"qualified_type\"\n            }\n          ]\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \",\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"type_reference_expression\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"qualified_type\"\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"_struct_body\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"struct_field_scope\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"struct_field_declaration\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"struct_field_scope\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"pub\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"mut\"\n            },\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"pub\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"mut\"\n                }\n              ]\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"__global\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \":\"\n        }\n      ]\n    },\n    \"struct_field_declaration\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_struct_field_definition\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"embedded_definition\"\n        }\n      ]\n    },\n    \"_struct_field_definition\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 8,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"identifier\"\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"type\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"=\"\n                  },\n                  {\n                    \"type\": \"FIELD\",\n                    \"name\": \"default_value\",\n                    \"content\": {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"_expression\"\n                    }\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"attributes\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"attribute\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"embedded_definition\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"type_reference_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"qualified_type\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"generic_type\"\n        }\n      ]\n    },\n    \"enum_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attributes\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"visibility_modifiers\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"enum\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"enum_backed_type\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_enum_body\"\n        }\n      ]\n    },\n    \"enum_backed_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"as\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"plain_type\"\n        }\n      ]\n    },\n    \"_enum_body\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"enum_field_definition\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\n\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\r\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"\\r\\n\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"enum_field_definition\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"=\"\n                },\n                {\n                  \"type\": \"FIELD\",\n                  \"name\": \"value\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_expression\"\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attribute\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        }\n      ]\n    },\n    \"interface_declaration\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"attributes\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"attributes\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"visibility_modifiers\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"interface\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"generic_parameters\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"generic_parameters\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_interface_body\"\n        }\n      ]\n    },\n    \"_interface_body\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"struct_field_scope\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"struct_field_declaration\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"interface_method_definition\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"interface_method_definition\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"identifier\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"generic_parameters\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"generic_parameters\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"signature\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"signature\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"attributes\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"attribute\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"_expression\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression_without_blocks\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression_with_blocks\"\n        }\n      ]\n    },\n    \"_expression_without_blocks\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"parenthesized_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"go_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"spawn_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"call_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"function_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"reference_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_max_group\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"array_creation\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"fixed_array_creation\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"unary_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"receive_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"binary_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"is_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"in_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"index_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"slice_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"as_type_cast_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"selector_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"enum_fetch\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"inc_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"dec_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"or_block_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"option_propagation_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"result_propagation_expression\"\n        }\n      ]\n    },\n    \"_expression_with_blocks\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"type_initializer\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"anon_struct_value_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"if_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"match_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"select_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"sql_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"lock_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"unsafe_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"compile_time_if_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"map_init_expression\"\n        }\n      ]\n    },\n    \"strictly_expression_list\": {\n      \"type\": \"PREC\",\n      \"value\": -2,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutable_expression\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \",\"\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_expression\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"mutable_expression\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"REPEAT\",\n                \"content\": {\n                  \"type\": \"SEQ\",\n                  \"members\": [\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \",\"\n                    },\n                    {\n                      \"type\": \"CHOICE\",\n                      \"members\": [\n                        {\n                          \"type\": \"SYMBOL\",\n                          \"name\": \"_expression\"\n                        },\n                        {\n                          \"type\": \"SYMBOL\",\n                          \"name\": \"mutable_expression\"\n                        }\n                      ]\n                    }\n                  ]\n                }\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"inc_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"++\"\n        }\n      ]\n    },\n    \"dec_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"--\"\n        }\n      ]\n    },\n    \"or_block_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"or_block\"\n        }\n      ]\n    },\n    \"option_propagation_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 9,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"?\"\n          }\n        ]\n      }\n    },\n    \"result_propagation_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 9,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"!\"\n          }\n        ]\n      }\n    },\n    \"anon_struct_value_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"struct\"\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"element_list\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"element_list\"\n              }\n            },\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"short_element_list\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"short_element_list\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"go_expression\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"go\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        ]\n      }\n    },\n    \"spawn_expression\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"spawn\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        ]\n      }\n    },\n    \"parenthesized_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"(\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"expression\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"call_expression\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"function\",\n                \"content\": {\n                  \"type\": \"TOKEN\",\n                  \"content\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"json.decode\"\n                  }\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"arguments\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"special_argument_list\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"name\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"FIELD\",\n                    \"name\": \"type_parameters\",\n                    \"content\": {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"type_parameters\"\n                    }\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"arguments\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"argument_list\"\n                }\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"type_parameters\": {\n      \"type\": \"PREC_DYNAMIC\",\n      \"value\": 2,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"IMMEDIATE_TOKEN\",\n            \"content\": {\n              \"type\": \"STRING\",\n              \"value\": \"[\"\n            }\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"plain_type\"\n              },\n              {\n                \"type\": \"REPEAT\",\n                \"content\": {\n                  \"type\": \"SEQ\",\n                  \"members\": [\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \",\"\n                    },\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"plain_type\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"]\"\n          }\n        ]\n      }\n    },\n    \"argument_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"(\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"argument\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"CHOICE\",\n                                \"members\": [\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"\\n\"\n                                  },\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"\\r\"\n                                  },\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"\\r\\n\"\n                                  }\n                                ]\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \";\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \",\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"short_lambda\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"short_lambda\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"|\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"reference_expression\"\n                },\n                {\n                  \"type\": \"REPEAT\",\n                  \"content\": {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \",\"\n                      },\n                      {\n                        \"type\": \"SYMBOL\",\n                        \"name\": \"reference_expression\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"|\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression_without_blocks\"\n        }\n      ]\n    },\n    \"argument\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"mutable_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"keyed_element\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"spread_expression\"\n        }\n      ]\n    },\n    \"special_argument_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"(\"\n        },\n        {\n          \"type\": \"ALIAS\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_plain_type_without_special\"\n          },\n          \"named\": true,\n          \"value\": \"plain_type\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \",\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"type_initializer\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 8,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"type\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"body\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"type_initializer_body\"\n            }\n          }\n        ]\n      }\n    },\n    \"type_initializer_body\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"FIELD\",\n                  \"name\": \"element_list\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"element_list\"\n                  }\n                },\n                {\n                  \"type\": \"FIELD\",\n                  \"name\": \"short_element_list\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"short_element_list\"\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"element_list\": {\n      \"type\": \"REPEAT1\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"spread_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"keyed_element\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"reference_expression\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \";\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"short_element_list\": {\n      \"type\": \"REPEAT1\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"ALIAS\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            },\n            \"named\": true,\n            \"value\": \"element\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \";\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"field_name\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"reference_expression\"\n    },\n    \"keyed_element\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"key\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"field_name\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \":\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        }\n      ]\n    },\n    \"function_literal\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"fn\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"capture_list\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"capture_list\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"generic_parameters\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"generic_parameters\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"signature\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"signature\"\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"body\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"block\"\n            }\n          }\n        ]\n      }\n    },\n    \"capture_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"[\"\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"capture\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"capture\"\n                  }\n                ]\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \",\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        }\n      ]\n    },\n    \"capture\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"mutability_modifiers\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"reference_expression\"\n        }\n      ]\n    },\n    \"reference_expression\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SYMBOL\",\n        \"name\": \"identifier\"\n      }\n    },\n    \"type_reference_expression\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SYMBOL\",\n        \"name\": \"identifier\"\n      }\n    },\n    \"unary_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 6,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operator\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"+\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"-\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"!\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"~\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"^\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"*\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"&\"\n                }\n              ]\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operand\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"receive_expression\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 6,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operator\",\n            \"content\": {\n              \"type\": \"STRING\",\n              \"value\": \"<-\"\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operand\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"binary_expression\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"PREC_LEFT\",\n          \"value\": 5,\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"left\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"operator\",\n                \"content\": {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"*\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"/\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"%\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"<<\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \">>\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \">>>\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"&\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"&^\"\n                    }\n                  ]\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"right\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"PREC_LEFT\",\n          \"value\": 4,\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"left\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"operator\",\n                \"content\": {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"+\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"-\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"|\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"^\"\n                    }\n                  ]\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"right\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"PREC_LEFT\",\n          \"value\": 3,\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"left\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"operator\",\n                \"content\": {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"==\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"!=\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"<\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"<=\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \">\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \">=\"\n                    }\n                  ]\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"right\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"PREC_LEFT\",\n          \"value\": 2,\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"left\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"operator\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"&&\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"right\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"PREC_LEFT\",\n          \"value\": 1,\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"left\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"operator\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"||\"\n                }\n              },\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"right\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"as_type_cast_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"as\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"plain_type\"\n        }\n      ]\n    },\n    \"or_block\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"or\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"block\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"_max_group\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"pseudo_compile_time_identifier\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"literal\"\n          }\n        ]\n      }\n    },\n    \"escape_sequence\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"PREC\",\n        \"value\": 1,\n        \"content\": {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"\\\\\"\n            },\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"u[a-fA-F\\\\d]{4}\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"U[a-fA-F\\\\d]{8}\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"x[a-fA-F\\\\d]{2}\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"\\\\d{3}\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"\\\\r?\\\\n\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"['\\\"abfrntv$\\\\\\\\]\"\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"\\\\S\"\n                }\n              ]\n            }\n          ]\n        }\n      }\n    },\n    \"literal\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"int_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"float_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_string_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"rune_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"none\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"true\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"false\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"nil\"\n        }\n      ]\n    },\n    \"none\": {\n      \"type\": \"STRING\",\n      \"value\": \"none\"\n    },\n    \"true\": {\n      \"type\": \"STRING\",\n      \"value\": \"true\"\n    },\n    \"false\": {\n      \"type\": \"STRING\",\n      \"value\": \"false\"\n    },\n    \"nil\": {\n      \"type\": \"STRING\",\n      \"value\": \"nil\"\n    },\n    \"spread_expression\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 6,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"...\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        ]\n      }\n    },\n    \"map_init_expression\": {\n      \"type\": \"PREC\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"{\"\n          },\n          {\n            \"type\": \"REPEAT\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"map_keyed_element\"\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"CHOICE\",\n                      \"members\": [\n                        {\n                          \"type\": \"CHOICE\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"\\n\"\n                                },\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"\\r\"\n                                },\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"\\r\\n\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"STRING\",\n                              \"value\": \";\"\n                            }\n                          ]\n                        },\n                        {\n                          \"type\": \"STRING\",\n                          \"value\": \",\"\n                        }\n                      ]\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                }\n              ]\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"}\"\n          }\n        ]\n      }\n    },\n    \"map_keyed_element\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"key\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \":\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        }\n      ]\n    },\n    \"array_creation\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 5,\n      \"content\": {\n        \"type\": \"SYMBOL\",\n        \"name\": \"_array\"\n      }\n    },\n    \"fixed_array_creation\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 5,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_array\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"!\"\n          }\n        ]\n      }\n    },\n    \"_array\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"[\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        }\n      ]\n    },\n    \"selector_expression\": {\n      \"type\": \"PREC_DYNAMIC\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"PREC\",\n        \"value\": 7,\n        \"content\": {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"operand\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              }\n            },\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \".\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"?.\"\n                }\n              ]\n            },\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"field\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"reference_expression\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"compile_time_selector_expression\"\n                  }\n                ]\n              }\n            }\n          ]\n        }\n      }\n    },\n    \"compile_time_selector_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"IMMEDIATE_TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"$(\"\n          }\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"field\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"reference_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"selector_expression\"\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"index_expression\": {\n      \"type\": \"PREC_DYNAMIC\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"PREC_RIGHT\",\n        \"value\": 7,\n        \"content\": {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"operand\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              }\n            },\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"[\"\n                },\n                {\n                  \"type\": \"IMMEDIATE_TOKEN\",\n                  \"content\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"[\"\n                  }\n                },\n                {\n                  \"type\": \"TOKEN\",\n                  \"content\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"#[\"\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"index\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"]\"\n            }\n          ]\n        }\n      }\n    },\n    \"slice_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operand\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"[\"\n              },\n              {\n                \"type\": \"IMMEDIATE_TOKEN\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"[\"\n                }\n              },\n              {\n                \"type\": \"TOKEN\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"#[\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"range\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"]\"\n          }\n        ]\n      }\n    },\n    \"if_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"if\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"condition\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              }\n            },\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"guard\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"var_declaration\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"block\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"else_branch\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        }\n      ]\n    },\n    \"else_branch\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"else\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"else_branch\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"block\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"block\"\n                }\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"if_expression\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"compile_time_if_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"$if\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"condition\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"?\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"block\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"$else\"\n                },\n                {\n                  \"type\": \"FIELD\",\n                  \"name\": \"else_branch\",\n                  \"content\": {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"SYMBOL\",\n                        \"name\": \"block\"\n                      },\n                      {\n                        \"type\": \"SYMBOL\",\n                        \"name\": \"compile_time_if_expression\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        }\n      ]\n    },\n    \"is_expression\": {\n      \"type\": \"PREC_DYNAMIC\",\n      \"value\": 2,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"left\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"mutability_modifiers\"\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              ]\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"is\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"!is\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"right\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            }\n          }\n        ]\n      }\n    },\n    \"in_expression\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 3,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"left\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"in\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"!in\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"right\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"enum_fetch\": {\n      \"type\": \"PREC_DYNAMIC\",\n      \"value\": -1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \".\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"reference_expression\"\n          }\n        ]\n      }\n    },\n    \"match_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"match\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"condition\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutable_expression\"\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"match_arms\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"match_arms\": {\n      \"type\": \"REPEAT1\",\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"match_arm\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"match_else_arm_clause\"\n          }\n        ]\n      }\n    },\n    \"match_arm\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"match_expression_list\"\n          }\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"block\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"match_expression_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression_without_blocks\"\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"match_arm_type\"\n            },\n            {\n              \"type\": \"ALIAS\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_definite_range\"\n              },\n              \"named\": true,\n              \"value\": \"range\"\n            }\n          ]\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \",\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_expression_without_blocks\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"match_arm_type\"\n                  },\n                  {\n                    \"type\": \"ALIAS\",\n                    \"content\": {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"_definite_range\"\n                    },\n                    \"named\": true,\n                    \"value\": \"range\"\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"match_arm_type\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"plain_type\"\n    },\n    \"match_else_arm_clause\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"else\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"block\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"select_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"select\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"selected_variables\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"expression_list\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"select_arm\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"select_else_arn_clause\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"select_arm\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"select_arm_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block\"\n        }\n      ]\n    },\n    \"select_arm_statement\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"ALIAS\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"select_var_declaration\"\n            },\n            \"named\": true,\n            \"value\": \"var_declaration\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"send_statement\"\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"ALIAS\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"expression_without_blocks_list\"\n                },\n                \"named\": true,\n                \"value\": \"expression_list\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_select_arm_assignment_statement\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"_select_arm_assignment_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"*=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"/=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"%=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"<<=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \">>=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \">>>=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"&=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"&^=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"+=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"-=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"|=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"^=\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"=\"\n            }\n          ]\n        },\n        {\n          \"type\": \"ALIAS\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"expression_without_blocks_list\"\n          },\n          \"named\": true,\n          \"value\": \"expression_list\"\n        }\n      ]\n    },\n    \"select_var_declaration\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"var_list\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"identifier_list\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \":=\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"expression_list\",\n            \"content\": {\n              \"type\": \"ALIAS\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"expression_without_blocks_list\"\n              },\n              \"named\": true,\n              \"value\": \"expression_list\"\n            }\n          }\n        ]\n      }\n    },\n    \"select_else_arn_clause\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"else\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block\"\n        }\n      ]\n    },\n    \"lock_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"lock\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"rlock\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"locked_variables\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"expression_list\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"body\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"unsafe_expression\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"unsafe\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block\"\n        }\n      ]\n    },\n    \"sql_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"sql\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"identifier\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_content_block\"\n          }\n        ]\n      }\n    },\n    \"int_literal\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"0\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"b\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"B\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"_\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[01]\"\n                  },\n                  {\n                    \"type\": \"REPEAT\",\n                    \"content\": {\n                      \"type\": \"SEQ\",\n                      \"members\": [\n                        {\n                          \"type\": \"CHOICE\",\n                          \"members\": [\n                            {\n                              \"type\": \"STRING\",\n                              \"value\": \"_\"\n                            },\n                            {\n                              \"type\": \"BLANK\"\n                            }\n                          ]\n                        },\n                        {\n                          \"type\": \"PATTERN\",\n                          \"value\": \"[01]\"\n                        }\n                      ]\n                    }\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"0\"\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[1-9]\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"_\"\n                              },\n                              {\n                                \"type\": \"BLANK\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"SEQ\",\n                            \"members\": [\n                              {\n                                \"type\": \"PATTERN\",\n                                \"value\": \"[0-9]\"\n                              },\n                              {\n                                \"type\": \"REPEAT\",\n                                \"content\": {\n                                  \"type\": \"SEQ\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"CHOICE\",\n                                      \"members\": [\n                                        {\n                                          \"type\": \"STRING\",\n                                          \"value\": \"_\"\n                                        },\n                                        {\n                                          \"type\": \"BLANK\"\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"type\": \"PATTERN\",\n                                      \"value\": \"[0-9]\"\n                                    }\n                                  ]\n                                }\n                              }\n                            ]\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"0\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"o\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"O\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"_\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[0-7]\"\n                  },\n                  {\n                    \"type\": \"REPEAT\",\n                    \"content\": {\n                      \"type\": \"SEQ\",\n                      \"members\": [\n                        {\n                          \"type\": \"CHOICE\",\n                          \"members\": [\n                            {\n                              \"type\": \"STRING\",\n                              \"value\": \"_\"\n                            },\n                            {\n                              \"type\": \"BLANK\"\n                            }\n                          ]\n                        },\n                        {\n                          \"type\": \"PATTERN\",\n                          \"value\": \"[0-7]\"\n                        }\n                      ]\n                    }\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"0\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"x\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"X\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"_\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[0-9a-fA-F]\"\n                  },\n                  {\n                    \"type\": \"REPEAT\",\n                    \"content\": {\n                      \"type\": \"SEQ\",\n                      \"members\": [\n                        {\n                          \"type\": \"CHOICE\",\n                          \"members\": [\n                            {\n                              \"type\": \"STRING\",\n                              \"value\": \"_\"\n                            },\n                            {\n                              \"type\": \"BLANK\"\n                            }\n                          ]\n                        },\n                        {\n                          \"type\": \"PATTERN\",\n                          \"value\": \"[0-9a-fA-F]\"\n                        }\n                      ]\n                    }\n                  }\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"float_literal\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[0-9]\"\n                      },\n                      {\n                        \"type\": \"REPEAT\",\n                        \"content\": {\n                          \"type\": \"SEQ\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"_\"\n                                },\n                                {\n                                  \"type\": \"BLANK\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"PATTERN\",\n                              \"value\": \"[0-9]\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \".\"\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[0-9]\"\n                      },\n                      {\n                        \"type\": \"REPEAT\",\n                        \"content\": {\n                          \"type\": \"SEQ\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"_\"\n                                },\n                                {\n                                  \"type\": \"BLANK\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"PATTERN\",\n                              \"value\": \"[0-9]\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"e\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"E\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"CHOICE\",\n                                \"members\": [\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"+\"\n                                  },\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"-\"\n                                  }\n                                ]\n                              },\n                              {\n                                \"type\": \"BLANK\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"SEQ\",\n                            \"members\": [\n                              {\n                                \"type\": \"PATTERN\",\n                                \"value\": \"[0-9]\"\n                              },\n                              {\n                                \"type\": \"REPEAT\",\n                                \"content\": {\n                                  \"type\": \"SEQ\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"CHOICE\",\n                                      \"members\": [\n                                        {\n                                          \"type\": \"STRING\",\n                                          \"value\": \"_\"\n                                        },\n                                        {\n                                          \"type\": \"BLANK\"\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"type\": \"PATTERN\",\n                                      \"value\": \"[0-9]\"\n                                    }\n                                  ]\n                                }\n                              }\n                            ]\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[0-9]\"\n                      },\n                      {\n                        \"type\": \"REPEAT\",\n                        \"content\": {\n                          \"type\": \"SEQ\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"_\"\n                                },\n                                {\n                                  \"type\": \"BLANK\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"PATTERN\",\n                              \"value\": \"[0-9]\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"e\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"E\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"+\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"-\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"BLANK\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9]\"\n                          },\n                          {\n                            \"type\": \"REPEAT\",\n                            \"content\": {\n                              \"type\": \"SEQ\",\n                              \"members\": [\n                                {\n                                  \"type\": \"CHOICE\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"STRING\",\n                                      \"value\": \"_\"\n                                    },\n                                    {\n                                      \"type\": \"BLANK\"\n                                    }\n                                  ]\n                                },\n                                {\n                                  \"type\": \"PATTERN\",\n                                  \"value\": \"[0-9]\"\n                                }\n                              ]\n                            }\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \".\"\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[0-9]\"\n                      },\n                      {\n                        \"type\": \"REPEAT\",\n                        \"content\": {\n                          \"type\": \"SEQ\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"_\"\n                                },\n                                {\n                                  \"type\": \"BLANK\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"PATTERN\",\n                              \"value\": \"[0-9]\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"e\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"E\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"CHOICE\",\n                                \"members\": [\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"+\"\n                                  },\n                                  {\n                                    \"type\": \"STRING\",\n                                    \"value\": \"-\"\n                                  }\n                                ]\n                              },\n                              {\n                                \"type\": \"BLANK\"\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"SEQ\",\n                            \"members\": [\n                              {\n                                \"type\": \"PATTERN\",\n                                \"value\": \"[0-9]\"\n                              },\n                              {\n                                \"type\": \"REPEAT\",\n                                \"content\": {\n                                  \"type\": \"SEQ\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"CHOICE\",\n                                      \"members\": [\n                                        {\n                                          \"type\": \"STRING\",\n                                          \"value\": \"_\"\n                                        },\n                                        {\n                                          \"type\": \"BLANK\"\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"type\": \"PATTERN\",\n                                      \"value\": \"[0-9]\"\n                                    }\n                                  ]\n                                }\n                              }\n                            ]\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"0\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"x\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"X\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"_\"\n                          },\n                          {\n                            \"type\": \"BLANK\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"REPEAT\",\n                            \"content\": {\n                              \"type\": \"SEQ\",\n                              \"members\": [\n                                {\n                                  \"type\": \"CHOICE\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"STRING\",\n                                      \"value\": \"_\"\n                                    },\n                                    {\n                                      \"type\": \"BLANK\"\n                                    }\n                                  ]\n                                },\n                                {\n                                  \"type\": \"PATTERN\",\n                                  \"value\": \"[0-9a-fA-F]\"\n                                }\n                              ]\n                            }\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \".\"\n                      },\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"SEQ\",\n                            \"members\": [\n                              {\n                                \"type\": \"PATTERN\",\n                                \"value\": \"[0-9a-fA-F]\"\n                              },\n                              {\n                                \"type\": \"REPEAT\",\n                                \"content\": {\n                                  \"type\": \"SEQ\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"CHOICE\",\n                                      \"members\": [\n                                        {\n                                          \"type\": \"STRING\",\n                                          \"value\": \"_\"\n                                        },\n                                        {\n                                          \"type\": \"BLANK\"\n                                        }\n                                      ]\n                                    },\n                                    {\n                                      \"type\": \"PATTERN\",\n                                      \"value\": \"[0-9a-fA-F]\"\n                                    }\n                                  ]\n                                }\n                              }\n                            ]\n                          },\n                          {\n                            \"type\": \"BLANK\"\n                          }\n                        ]\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"_\"\n                          },\n                          {\n                            \"type\": \"BLANK\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"REPEAT\",\n                            \"content\": {\n                              \"type\": \"SEQ\",\n                              \"members\": [\n                                {\n                                  \"type\": \"CHOICE\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"STRING\",\n                                      \"value\": \"_\"\n                                    },\n                                    {\n                                      \"type\": \"BLANK\"\n                                    }\n                                  ]\n                                },\n                                {\n                                  \"type\": \"PATTERN\",\n                                  \"value\": \"[0-9a-fA-F]\"\n                                }\n                              ]\n                            }\n                          }\n                        ]\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \".\"\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"REPEAT\",\n                            \"content\": {\n                              \"type\": \"SEQ\",\n                              \"members\": [\n                                {\n                                  \"type\": \"CHOICE\",\n                                  \"members\": [\n                                    {\n                                      \"type\": \"STRING\",\n                                      \"value\": \"_\"\n                                    },\n                                    {\n                                      \"type\": \"BLANK\"\n                                    }\n                                  ]\n                                },\n                                {\n                                  \"type\": \"PATTERN\",\n                                  \"value\": \"[0-9a-fA-F]\"\n                                }\n                              ]\n                            }\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"p\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"P\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"+\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"-\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"BLANK\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"SEQ\",\n                    \"members\": [\n                      {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[0-9]\"\n                      },\n                      {\n                        \"type\": \"REPEAT\",\n                        \"content\": {\n                          \"type\": \"SEQ\",\n                          \"members\": [\n                            {\n                              \"type\": \"CHOICE\",\n                              \"members\": [\n                                {\n                                  \"type\": \"STRING\",\n                                  \"value\": \"_\"\n                                },\n                                {\n                                  \"type\": \"BLANK\"\n                                }\n                              ]\n                            },\n                            {\n                              \"type\": \"PATTERN\",\n                              \"value\": \"[0-9]\"\n                            }\n                          ]\n                        }\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"rune_literal\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"`\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"PATTERN\",\n                \"value\": \"[^'\\\\\\\\]\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"'\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"\\\"\"\n              },\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"\\\\\"\n                  },\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"0\"\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \"`\"\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"x\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-7]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-7]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-7]\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"u\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"U\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          },\n                          {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[0-9a-fA-F]\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"SEQ\",\n                        \"members\": [\n                          {\n                            \"type\": \"CHOICE\",\n                            \"members\": [\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"a\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"b\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"e\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"f\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"n\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"r\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"t\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"v\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\\\\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"'\"\n                              },\n                              {\n                                \"type\": \"STRING\",\n                                \"value\": \"\\\"\"\n                              }\n                            ]\n                          }\n                        ]\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"`\"\n          }\n        ]\n      }\n    },\n    \"_string_literal\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"interpreted_string_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"c_string_literal\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"raw_string_literal\"\n        }\n      ]\n    },\n    \"interpreted_string_literal\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"'\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"IMMEDIATE_TOKEN\",\n                    \"content\": {\n                      \"type\": \"PREC_RIGHT\",\n                      \"value\": 1,\n                      \"content\": {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[^'\\\\\\\\$]+\"\n                      }\n                    }\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"$\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"escape_sequence\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"string_interpolation\"\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"'\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"\\\"\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"IMMEDIATE_TOKEN\",\n                    \"content\": {\n                      \"type\": \"PREC_RIGHT\",\n                      \"value\": 1,\n                      \"content\": {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[^\\\"\\\\\\\\$]+\"\n                      }\n                    }\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"$\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"escape_sequence\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"string_interpolation\"\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"\\\"\"\n            }\n          ]\n        }\n      ]\n    },\n    \"c_string_literal\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"c'\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"IMMEDIATE_TOKEN\",\n                    \"content\": {\n                      \"type\": \"PREC_RIGHT\",\n                      \"value\": 1,\n                      \"content\": {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[^'\\\\\\\\$]+\"\n                      }\n                    }\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"$\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"escape_sequence\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"string_interpolation\"\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"'\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"c\\\"\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"IMMEDIATE_TOKEN\",\n                    \"content\": {\n                      \"type\": \"PREC_RIGHT\",\n                      \"value\": 1,\n                      \"content\": {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[^\\\"\\\\\\\\$]+\"\n                      }\n                    }\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"$\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"escape_sequence\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"string_interpolation\"\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"\\\"\"\n            }\n          ]\n        }\n      ]\n    },\n    \"raw_string_literal\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"r'\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"IMMEDIATE_TOKEN\",\n                \"content\": {\n                  \"type\": \"PREC_RIGHT\",\n                  \"value\": 1,\n                  \"content\": {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[^']+\"\n                  }\n                }\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"'\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"r\\\"\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"IMMEDIATE_TOKEN\",\n                \"content\": {\n                  \"type\": \"PREC_RIGHT\",\n                  \"value\": 1,\n                  \"content\": {\n                    \"type\": \"PATTERN\",\n                    \"value\": \"[^\\\"]+\"\n                  }\n                }\n              }\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"\\\"\"\n            }\n          ]\n        }\n      ]\n    },\n    \"string_interpolation\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"ALIAS\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"${\"\n          },\n          \"named\": true,\n          \"value\": \"interpolation_opening\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"ALIAS\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                },\n                \"named\": true,\n                \"value\": \"interpolation_expression\"\n              }\n            },\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"ALIAS\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_expression\"\n                  },\n                  \"named\": true,\n                  \"value\": \"interpolation_expression\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"format_specifier\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"type\": \"ALIAS\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \"}\"\n          },\n          \"named\": true,\n          \"value\": \"interpolation_closing\"\n        }\n      ]\n    },\n    \"format_specifier\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"TOKEN\",\n          \"content\": {\n            \"type\": \"STRING\",\n            \"value\": \":\"\n          }\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"TOKEN\",\n              \"content\": {\n                \"type\": \"PATTERN\",\n                \"value\": \"[bgGeEfFcdoxXpsS]\"\n              }\n            },\n            {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"CHOICE\",\n                      \"members\": [\n                        {\n                          \"type\": \"TOKEN\",\n                          \"content\": {\n                            \"type\": \"PATTERN\",\n                            \"value\": \"[+\\\\-]\"\n                          }\n                        },\n                        {\n                          \"type\": \"TOKEN\",\n                          \"content\": {\n                            \"type\": \"STRING\",\n                            \"value\": \"0\"\n                          }\n                        }\n                      ]\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"int_literal\"\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"SEQ\",\n                      \"members\": [\n                        {\n                          \"type\": \"STRING\",\n                          \"value\": \".\"\n                        },\n                        {\n                          \"type\": \"SYMBOL\",\n                          \"name\": \"int_literal\"\n                        }\n                      ]\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"TOKEN\",\n                      \"content\": {\n                        \"type\": \"PATTERN\",\n                        \"value\": \"[bgGeEfFcdoxXpsS]\"\n                      }\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"pseudo_compile_time_identifier\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"@\"\n          },\n          {\n            \"type\": \"ALIAS\",\n            \"content\": {\n              \"type\": \"IMMEDIATE_TOKEN\",\n              \"content\": {\n                \"type\": \"PATTERN\",\n                \"value\": \"[A-Z][A-Z0-9_]+\"\n              }\n            },\n            \"named\": true,\n            \"value\": \"identifier\"\n          }\n        ]\n      }\n    },\n    \"identifier\": {\n      \"type\": \"TOKEN\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"@\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"$\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"C.\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"JS.\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"PATTERN\",\n                \"value\": \"[a-zA-Zα-ωΑ-Ωµ]\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"_\"\n              }\n            ]\n          },\n          {\n            \"type\": \"REPEAT\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"PATTERN\",\n                      \"value\": \"[a-zA-Zα-ωΑ-Ωµ]\"\n                    },\n                    {\n                      \"type\": \"STRING\",\n                      \"value\": \"_\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"PATTERN\",\n                  \"value\": \"[0-9]\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"visibility_modifiers\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"pub\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"__global\"\n          }\n        ]\n      }\n    },\n    \"mutability_modifiers\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"mut\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"static\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"volatile\"\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"shared\"\n          }\n        ]\n      }\n    },\n    \"mutable_identifier\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"mutability_modifiers\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"identifier\"\n          }\n        ]\n      }\n    },\n    \"mutable_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"mutability_modifiers\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          }\n        ]\n      }\n    },\n    \"identifier_list\": {\n      \"type\": \"PREC\",\n      \"value\": 2,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutable_identifier\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"identifier\"\n              }\n            ]\n          },\n          {\n            \"type\": \"REPEAT\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \",\"\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"mutable_identifier\"\n                    },\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"identifier\"\n                    }\n                  ]\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"expression_list\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"mutable_expression\"\n              }\n            ]\n          },\n          {\n            \"type\": \"REPEAT\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \",\"\n                },\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"_expression\"\n                    },\n                    {\n                      \"type\": \"SYMBOL\",\n                      \"name\": \"mutable_expression\"\n                    }\n                  ]\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"expression_without_blocks_list\": {\n      \"type\": \"PREC\",\n      \"value\": 1,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression_without_blocks\"\n          },\n          {\n            \"type\": \"REPEAT\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \",\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression_without_blocks\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"sum_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          },\n          {\n            \"type\": \"REPEAT1\",\n            \"content\": {\n              \"type\": \"SEQ\",\n              \"members\": [\n                {\n                  \"type\": \"CHOICE\",\n                  \"members\": [\n                    {\n                      \"type\": \"PATTERN\",\n                      \"value\": \"\\\\s+\"\n                    },\n                    {\n                      \"type\": \"BLANK\"\n                    }\n                  ]\n                },\n                {\n                  \"type\": \"IMMEDIATE_TOKEN\",\n                  \"content\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"|\"\n                  }\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"plain_type\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"plain_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_plain_type_without_special\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"option_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"result_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"multi_return_type\"\n          }\n        ]\n      }\n    },\n    \"_plain_type_without_special\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"type_reference_expression\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"qualified_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"pointer_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"wrong_pointer_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"array_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"fixed_array_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"function_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"generic_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"map_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"channel_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"shared_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"thread_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"atomic_type\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"anon_struct_type\"\n          }\n        ]\n      }\n    },\n    \"anon_struct_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"struct\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_struct_body\"\n        }\n      ]\n    },\n    \"multi_return_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"(\"\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"plain_type\"\n                  }\n                ]\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \",\"\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \")\"\n        }\n      ]\n    },\n    \"result_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"!\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"plain_type\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"option_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"?\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"plain_type\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"qualified_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"module\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"reference_expression\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \".\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"name\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"type_reference_expression\"\n          }\n        }\n      ]\n    },\n    \"fixed_array_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"[\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"size\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"int_literal\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"reference_expression\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"selector_expression\"\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"element\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        }\n      ]\n    },\n    \"array_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"[\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"]\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"element\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"plain_type\"\n            }\n          }\n        ]\n      }\n    },\n    \"pointer_type\": {\n      \"type\": \"PREC\",\n      \"value\": 9,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"&\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        ]\n      }\n    },\n    \"wrong_pointer_type\": {\n      \"type\": \"PREC\",\n      \"value\": 9,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"*\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        ]\n      }\n    },\n    \"map_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"map[\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"key\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"value\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        }\n      ]\n    },\n    \"channel_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"chan\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"plain_type\"\n          }\n        ]\n      }\n    },\n    \"shared_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"shared\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"plain_type\"\n        }\n      ]\n    },\n    \"thread_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"thread\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"plain_type\"\n        }\n      ]\n    },\n    \"atomic_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"atomic\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"plain_type\"\n        }\n      ]\n    },\n    \"generic_type\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"qualified_type\"\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"type_reference_expression\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"type_parameters\"\n        }\n      ]\n    },\n    \"function_type\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"fn\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"signature\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"signature\"\n            }\n          }\n        ]\n      }\n    },\n    \"_statement\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"simple_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"assert_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"continue_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"break_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"return_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"asm_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"goto_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"labeled_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"defer_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"for_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"compile_time_for_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"send_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"hash_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"append_statement\"\n        }\n      ]\n    },\n    \"simple_statement\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"var_declaration\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_expression\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"assignment_statement\"\n        },\n        {\n          \"type\": \"ALIAS\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"strictly_expression_list\"\n          },\n          \"named\": true,\n          \"value\": \"expression_list\"\n        }\n      ]\n    },\n    \"assert_statement\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"assert\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_expression\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \",\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_expression\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"append_statement\": {\n      \"type\": \"PREC\",\n      \"value\": 6,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"left\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"<<\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"right\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"send_statement\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"channel\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"<-\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"value\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"var_declaration\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"var_list\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"expression_list\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \":=\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"expression_list\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"expression_list\"\n            }\n          }\n        ]\n      }\n    },\n    \"var_definition_list\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"var_definition\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \",\"\n              },\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"var_definition\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"var_definition\": {\n      \"type\": \"PREC\",\n      \"value\": 8,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"modifiers\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"mut\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"name\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"identifier\"\n            }\n          }\n        ]\n      }\n    },\n    \"assignment_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"left\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"expression_list\"\n          }\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"operator\",\n          \"content\": {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"*=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"/=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"%=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"<<=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \">>=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \">>>=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"&=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"&^=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"+=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"-=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"|=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"^=\"\n              },\n              {\n                \"type\": \"STRING\",\n                \"value\": \"=\"\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"right\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"expression_list\"\n          }\n        }\n      ]\n    },\n    \"_block_element\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_statement\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"import_list\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_top_level_declaration\"\n        }\n      ]\n    },\n    \"block\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"REPEAT\",\n          \"content\": {\n            \"type\": \"SEQ\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_block_element\"\n              },\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"CHOICE\",\n                    \"members\": [\n                      {\n                        \"type\": \"CHOICE\",\n                        \"members\": [\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\n\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\"\n                          },\n                          {\n                            \"type\": \"STRING\",\n                            \"value\": \"\\r\\n\"\n                          }\n                        ]\n                      },\n                      {\n                        \"type\": \"STRING\",\n                        \"value\": \";\"\n                      }\n                    ]\n                  },\n                  {\n                    \"type\": \"BLANK\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"defer_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"defer\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"block\"\n        }\n      ]\n    },\n    \"label_reference\": {\n      \"type\": \"SYMBOL\",\n      \"name\": \"identifier\"\n    },\n    \"goto_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"goto\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"label_reference\"\n        }\n      ]\n    },\n    \"break_statement\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"break\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"label_reference\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"continue_statement\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"continue\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"label_reference\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"return_statement\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"return\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"expression_list\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"expression_list\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"label_definition\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"identifier\"\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \":\"\n        }\n      ]\n    },\n    \"labeled_statement\": {\n      \"type\": \"PREC_RIGHT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"label_definition\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"SYMBOL\",\n                \"name\": \"_statement\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"compile_time_for_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"$for\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"range_clause\"\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"body\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"for_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"for\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"range_clause\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"for_clause\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"is_clause\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              ]\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"FIELD\",\n          \"name\": \"body\",\n          \"content\": {\n            \"type\": \"SYMBOL\",\n            \"name\": \"block\"\n          }\n        }\n      ]\n    },\n    \"is_clause\": {\n      \"type\": \"PREC\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"ALIAS\",\n                \"content\": {\n                  \"type\": \"STRING\",\n                  \"value\": \"mut\"\n                },\n                \"named\": true,\n                \"value\": \"mutability_modifiers\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"is_expression\"\n          }\n        ]\n      }\n    },\n    \"range_clause\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 7,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"left\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"var_definition_list\"\n            }\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \"in\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"right\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"ALIAS\",\n                  \"content\": {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"_definite_range\"\n                  },\n                  \"named\": true,\n                  \"value\": \"range\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    \"for_clause\": {\n      \"type\": \"PREC_LEFT\",\n      \"value\": 0,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"initializer\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"simple_statement\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \";\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"condition\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \";\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"update\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"simple_statement\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"_definite_range\": {\n      \"type\": \"PREC\",\n      \"value\": 5,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"start\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operator\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"..\"\n                },\n                {\n                  \"type\": \"STRING\",\n                  \"value\": \"...\"\n                }\n              ]\n            }\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"end\",\n            \"content\": {\n              \"type\": \"SYMBOL\",\n              \"name\": \"_expression\"\n            }\n          }\n        ]\n      }\n    },\n    \"range\": {\n      \"type\": \"PREC\",\n      \"value\": 5,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"start\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"operator\",\n            \"content\": {\n              \"type\": \"STRING\",\n              \"value\": \"..\"\n            }\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"FIELD\",\n                \"name\": \"end\",\n                \"content\": {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"_expression\"\n                }\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"hash_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"#\"\n        },\n        {\n          \"type\": \"IMMEDIATE_TOKEN\",\n          \"content\": {\n            \"type\": \"REPEAT1\",\n            \"content\": {\n              \"type\": \"PATTERN\",\n              \"value\": \"[^\\\\\\\\\\\\r\\\\n]\"\n            }\n          }\n        }\n      ]\n    },\n    \"asm_statement\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"asm\"\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"modifiers\",\n              \"content\": {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"volatile\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"goto\"\n                  }\n                ]\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"FIELD\",\n              \"name\": \"arch\",\n              \"content\": {\n                \"type\": \"SYMBOL\",\n                \"name\": \"identifier\"\n              }\n            },\n            {\n              \"type\": \"BLANK\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"_content_block\"\n        }\n      ]\n    },\n    \"_content_block\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"STRING\",\n          \"value\": \"{\"\n        },\n        {\n          \"type\": \"IMMEDIATE_TOKEN\",\n          \"content\": {\n            \"type\": \"PREC\",\n            \"value\": 1,\n            \"content\": {\n              \"type\": \"PATTERN\",\n              \"value\": \"[^{}]+\"\n            }\n          }\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"}\"\n        }\n      ]\n    },\n    \"attributes\": {\n      \"type\": \"REPEAT1\",\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"attribute\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"CHOICE\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"\\n\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"\\r\"\n                  },\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \"\\r\\n\"\n                  }\n                ]\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"attribute\": {\n      \"type\": \"SEQ\",\n      \"members\": [\n        {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"STRING\",\n              \"value\": \"[\"\n            },\n            {\n              \"type\": \"STRING\",\n              \"value\": \"@[\"\n            }\n          ]\n        },\n        {\n          \"type\": \"SEQ\",\n          \"members\": [\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"attribute_expression\"\n            },\n            {\n              \"type\": \"REPEAT\",\n              \"content\": {\n                \"type\": \"SEQ\",\n                \"members\": [\n                  {\n                    \"type\": \"STRING\",\n                    \"value\": \";\"\n                  },\n                  {\n                    \"type\": \"SYMBOL\",\n                    \"name\": \"attribute_expression\"\n                  }\n                ]\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"STRING\",\n          \"value\": \"]\"\n        }\n      ]\n    },\n    \"attribute_expression\": {\n      \"type\": \"PREC\",\n      \"value\": 10,\n      \"content\": {\n        \"type\": \"CHOICE\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"if_attribute\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"_plain_attribute\"\n          }\n        ]\n      }\n    },\n    \"if_attribute\": {\n      \"type\": \"PREC\",\n      \"value\": 10,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"STRING\",\n            \"value\": \"if\"\n          },\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"reference_expression\"\n          },\n          {\n            \"type\": \"CHOICE\",\n            \"members\": [\n              {\n                \"type\": \"STRING\",\n                \"value\": \"?\"\n              },\n              {\n                \"type\": \"BLANK\"\n              }\n            ]\n          }\n        ]\n      }\n    },\n    \"_plain_attribute\": {\n      \"type\": \"CHOICE\",\n      \"members\": [\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"literal_attribute\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"value_attribute\"\n        },\n        {\n          \"type\": \"SYMBOL\",\n          \"name\": \"key_value_attribute\"\n        }\n      ]\n    },\n    \"literal_attribute\": {\n      \"type\": \"PREC\",\n      \"value\": 10,\n      \"content\": {\n        \"type\": \"SYMBOL\",\n        \"name\": \"literal\"\n      }\n    },\n    \"value_attribute\": {\n      \"type\": \"PREC\",\n      \"value\": 10,\n      \"content\": {\n        \"type\": \"FIELD\",\n        \"name\": \"name\",\n        \"content\": {\n          \"type\": \"CHOICE\",\n          \"members\": [\n            {\n              \"type\": \"ALIAS\",\n              \"content\": {\n                \"type\": \"STRING\",\n                \"value\": \"unsafe\"\n              },\n              \"named\": true,\n              \"value\": \"reference_expression\"\n            },\n            {\n              \"type\": \"SYMBOL\",\n              \"name\": \"reference_expression\"\n            }\n          ]\n        }\n      }\n    },\n    \"key_value_attribute\": {\n      \"type\": \"PREC\",\n      \"value\": 10,\n      \"content\": {\n        \"type\": \"SEQ\",\n        \"members\": [\n          {\n            \"type\": \"SYMBOL\",\n            \"name\": \"value_attribute\"\n          },\n          {\n            \"type\": \"STRING\",\n            \"value\": \":\"\n          },\n          {\n            \"type\": \"FIELD\",\n            \"name\": \"value\",\n            \"content\": {\n              \"type\": \"CHOICE\",\n              \"members\": [\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"literal\"\n                },\n                {\n                  \"type\": \"SYMBOL\",\n                  \"name\": \"identifier\"\n                }\n              ]\n            }\n          }\n        ]\n      }\n    }\n  },\n  \"extras\": [\n    {\n      \"type\": \"PATTERN\",\n      \"value\": \"\\\\s\"\n    },\n    {\n      \"type\": \"SYMBOL\",\n      \"name\": \"line_comment\"\n    },\n    {\n      \"type\": \"SYMBOL\",\n      \"name\": \"block_comment\"\n    }\n  ],\n  \"conflicts\": [\n    [\n      \"fixed_array_type\",\n      \"_expression_without_blocks\"\n    ],\n    [\n      \"qualified_type\",\n      \"_expression_without_blocks\"\n    ],\n    [\n      \"fixed_array_type\",\n      \"literal\"\n    ],\n    [\n      \"reference_expression\",\n      \"type_reference_expression\"\n    ],\n    [\n      \"is_expression\"\n    ],\n    [\n      \"_expression_without_blocks\",\n      \"element_list\"\n    ]\n  ],\n  \"precedences\": [],\n  \"externals\": [],\n  \"inline\": [\n    \"_string_literal\",\n    \"_top_level_declaration\",\n    \"_array\"\n  ],\n  \"supertypes\": [\n    \"_expression\",\n    \"_statement\",\n    \"_top_level_declaration\",\n    \"_expression_with_blocks\"\n  ],\n  \"reserved\": {}\n}"
  },
  {
    "path": "tree_sitter_v/src/node-types.json",
    "content": "[\n  {\n    \"type\": \"_expression\",\n    \"named\": true,\n    \"subtypes\": [\n      {\n        \"type\": \"_expression_with_blocks\",\n        \"named\": true\n      },\n      {\n        \"type\": \"array_creation\",\n        \"named\": true\n      },\n      {\n        \"type\": \"as_type_cast_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"binary_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"call_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"dec_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"enum_fetch\",\n        \"named\": true\n      },\n      {\n        \"type\": \"fixed_array_creation\",\n        \"named\": true\n      },\n      {\n        \"type\": \"function_literal\",\n        \"named\": true\n      },\n      {\n        \"type\": \"go_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"in_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"inc_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"index_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"is_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"literal\",\n        \"named\": true\n      },\n      {\n        \"type\": \"option_propagation_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"or_block_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"parenthesized_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"pseudo_compile_time_identifier\",\n        \"named\": true\n      },\n      {\n        \"type\": \"receive_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"reference_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"result_propagation_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"selector_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"slice_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"spawn_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"unary_expression\",\n        \"named\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"_expression_with_blocks\",\n    \"named\": true,\n    \"subtypes\": [\n      {\n        \"type\": \"anon_struct_value_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"compile_time_if_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"if_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"lock_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"map_init_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"match_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"select_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"sql_expression\",\n        \"named\": true\n      },\n      {\n        \"type\": \"type_initializer\",\n        \"named\": true\n      },\n      {\n        \"type\": \"unsafe_expression\",\n        \"named\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"_statement\",\n    \"named\": true,\n    \"subtypes\": [\n      {\n        \"type\": \"append_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"asm_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"assert_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"block\",\n        \"named\": true\n      },\n      {\n        \"type\": \"break_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"compile_time_for_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"continue_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"defer_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"for_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"goto_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"hash_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"labeled_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"return_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"send_statement\",\n        \"named\": true\n      },\n      {\n        \"type\": \"simple_statement\",\n        \"named\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"_top_level_declaration\",\n    \"named\": true,\n    \"subtypes\": [\n      {\n        \"type\": \"const_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"enum_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"function_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"global_var_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"interface_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"static_method_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"struct_declaration\",\n        \"named\": true\n      },\n      {\n        \"type\": \"type_declaration\",\n        \"named\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"anon_struct_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"struct_field_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"struct_field_scope\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"anon_struct_value_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"element_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"element_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"short_element_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"short_element_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"append_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"argument\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"keyed_element\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutable_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"spread_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"argument_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"argument\",\n          \"named\": true\n        },\n        {\n          \"type\": \"short_lambda\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"array_creation\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"array_type\",\n    \"named\": true,\n    \"fields\": {\n      \"element\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"as_type_cast_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"asm_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"arch\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"modifiers\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"goto\",\n            \"named\": false\n          },\n          {\n            \"type\": \"volatile\",\n            \"named\": false\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"assert_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"assignment_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operator\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"%=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&^=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"*=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"+=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"-=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"/=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"<<=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"=\",\n            \"named\": false\n          },\n          {\n            \"type\": \">>=\",\n            \"named\": false\n          },\n          {\n            \"type\": \">>>=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"^=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"|=\",\n            \"named\": false\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"atomic_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"attribute\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"attribute_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"attribute_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"if_attribute\",\n          \"named\": true\n        },\n        {\n          \"type\": \"key_value_attribute\",\n          \"named\": true\n        },\n        {\n          \"type\": \"literal_attribute\",\n          \"named\": true\n        },\n        {\n          \"type\": \"value_attribute\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"attributes\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"attribute\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"binary_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operator\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"!=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"%\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&&\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&^\",\n            \"named\": false\n          },\n          {\n            \"type\": \"*\",\n            \"named\": false\n          },\n          {\n            \"type\": \"+\",\n            \"named\": false\n          },\n          {\n            \"type\": \"-\",\n            \"named\": false\n          },\n          {\n            \"type\": \"/\",\n            \"named\": false\n          },\n          {\n            \"type\": \"<\",\n            \"named\": false\n          },\n          {\n            \"type\": \"<<\",\n            \"named\": false\n          },\n          {\n            \"type\": \"<=\",\n            \"named\": false\n          },\n          {\n            \"type\": \"==\",\n            \"named\": false\n          },\n          {\n            \"type\": \">\",\n            \"named\": false\n          },\n          {\n            \"type\": \">=\",\n            \"named\": false\n          },\n          {\n            \"type\": \">>\",\n            \"named\": false\n          },\n          {\n            \"type\": \">>>\",\n            \"named\": false\n          },\n          {\n            \"type\": \"^\",\n            \"named\": false\n          },\n          {\n            \"type\": \"|\",\n            \"named\": false\n          },\n          {\n            \"type\": \"||\",\n            \"named\": false\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"block\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"_statement\",\n          \"named\": true\n        },\n        {\n          \"type\": \"_top_level_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"import_list\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"block_comment\",\n    \"named\": true,\n    \"extra\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"break_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"label_reference\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"c_string_literal\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"escape_sequence\",\n          \"named\": true\n        },\n        {\n          \"type\": \"string_interpolation\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"call_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"arguments\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"argument_list\",\n            \"named\": true\n          },\n          {\n            \"type\": \"special_argument_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"function\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"json.decode\",\n            \"named\": false\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"type_parameters\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"capture\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"mutability_modifiers\",\n          \"named\": true\n        },\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"capture_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"capture\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"channel_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"compile_time_for_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"body\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"range_clause\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"compile_time_if_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"condition\": {\n        \"multiple\": true,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"?\",\n            \"named\": false\n          },\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"else_branch\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          },\n          {\n            \"type\": \"compile_time_if_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"compile_time_selector_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"field\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"reference_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"selector_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"const_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"const_definition\",\n          \"named\": true\n        },\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"const_definition\",\n    \"named\": true,\n    \"fields\": {\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"continue_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"label_reference\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"dec_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"defer_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"block\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"element_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"keyed_element\",\n          \"named\": true\n        },\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"spread_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"else_branch\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"else_branch\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"if_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"embedded_definition\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"generic_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"qualified_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"type_reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"enum_backed_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"enum_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"enum_backed_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"enum_field_definition\",\n          \"named\": true\n        },\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"enum_fetch\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"enum_field_definition\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attribute\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"expression_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutable_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"field_name\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"fixed_array_creation\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"fixed_array_type\",\n    \"named\": true,\n    \"fields\": {\n      \"element\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      },\n      \"size\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"int_literal\",\n            \"named\": true\n          },\n          {\n            \"type\": \"reference_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"selector_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"for_clause\",\n    \"named\": true,\n    \"fields\": {\n      \"condition\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"initializer\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"simple_statement\",\n            \"named\": true\n          }\n        ]\n      },\n      \"update\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"simple_statement\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"for_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"body\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"for_clause\",\n          \"named\": true\n        },\n        {\n          \"type\": \"is_clause\",\n          \"named\": true\n        },\n        {\n          \"type\": \"range_clause\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"format_specifier\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"int_literal\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"function_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      },\n      \"body\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          },\n          {\n            \"type\": \"overridable_operator\",\n            \"named\": true\n          }\n        ]\n      },\n      \"receiver\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"receiver\",\n            \"named\": true\n          }\n        ]\n      },\n      \"signature\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"signature\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"function_literal\",\n    \"named\": true,\n    \"fields\": {\n      \"body\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"capture_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"capture_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"signature\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"signature\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"function_type\",\n    \"named\": true,\n    \"fields\": {\n      \"signature\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"signature\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"generic_parameter\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"generic_parameters\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"generic_parameter\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"generic_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"qualified_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"type_parameters\",\n          \"named\": true\n        },\n        {\n          \"type\": \"type_reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"global_var_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"global_var_definition\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"global_var_definition\",\n    \"named\": true,\n    \"fields\": {\n      \"modifiers\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"volatile\",\n            \"named\": false\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"go_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"goto_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"label_reference\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"hash_statement\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"identifier_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutable_identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"if_attribute\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"if_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"condition\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"guard\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"var_declaration\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"else_branch\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"implements_clause\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"qualified_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"type_reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_alias\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"import_name\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_declaration\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"import_spec\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"import_declaration\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_name\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_path\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"import_name\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"import_spec\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"import_alias\",\n          \"named\": true\n        },\n        {\n          \"type\": \"import_path\",\n          \"named\": true\n        },\n        {\n          \"type\": \"selective_import_list\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"in_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"inc_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"index_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"index\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operand\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"interface_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"interface_method_definition\",\n          \"named\": true\n        },\n        {\n          \"type\": \"struct_field_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"struct_field_scope\",\n          \"named\": true\n        },\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"interface_method_definition\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attribute\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"signature\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"signature\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"interpreted_string_literal\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"escape_sequence\",\n          \"named\": true\n        },\n        {\n          \"type\": \"string_interpolation\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"is_clause\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"is_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutability_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"is_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": true,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"mutability_modifiers\",\n            \"named\": true\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"key_value_attribute\",\n    \"named\": true,\n    \"fields\": {\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          },\n          {\n            \"type\": \"literal\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"value_attribute\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"keyed_element\",\n    \"named\": true,\n    \"fields\": {\n      \"key\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"field_name\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"label_definition\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"label_reference\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"labeled_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_statement\",\n          \"named\": true\n        },\n        {\n          \"type\": \"label_definition\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"line_comment\",\n    \"named\": true,\n    \"extra\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"literal\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"c_string_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"false\",\n          \"named\": true\n        },\n        {\n          \"type\": \"float_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"int_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"interpreted_string_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"nil\",\n          \"named\": true\n        },\n        {\n          \"type\": \"none\",\n          \"named\": true\n        },\n        {\n          \"type\": \"raw_string_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"rune_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"true\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"literal_attribute\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"literal\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"lock_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"body\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"locked_variables\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"map_init_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"map_keyed_element\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"map_keyed_element\",\n    \"named\": true,\n    \"fields\": {\n      \"key\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"map_type\",\n    \"named\": true,\n    \"fields\": {\n      \"key\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"match_arm\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"match_expression_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"match_arm_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"match_arms\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"match_arm\",\n          \"named\": true\n        },\n        {\n          \"type\": \"match_else_arm_clause\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"match_else_arm_clause\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"match_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"condition\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"mutable_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"match_arms\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"match_expression_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"array_creation\",\n          \"named\": true\n        },\n        {\n          \"type\": \"as_type_cast_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"binary_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"call_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"dec_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"enum_fetch\",\n          \"named\": true\n        },\n        {\n          \"type\": \"fixed_array_creation\",\n          \"named\": true\n        },\n        {\n          \"type\": \"function_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"go_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"in_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"inc_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"index_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"is_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"match_arm_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"option_propagation_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"or_block_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"parenthesized_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"pseudo_compile_time_identifier\",\n          \"named\": true\n        },\n        {\n          \"type\": \"range\",\n          \"named\": true\n        },\n        {\n          \"type\": \"receive_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"result_propagation_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"selector_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"slice_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"spawn_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"unary_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"module_clause\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"attributes\",\n          \"named\": true\n        },\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"multi_return_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"mutability_modifiers\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"mutable_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutability_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"mutable_identifier\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        },\n        {\n          \"type\": \"mutability_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"option_propagation_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"option_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"or_block\",\n    \"named\": true,\n    \"fields\": {\n      \"block\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"or_block_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"or_block\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"overridable_operator\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"parameter_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"mutability\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"mutability_modifiers\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      },\n      \"variadic\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"...\",\n            \"named\": false\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"parameter_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"parameter_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"variadic_parameter\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"parenthesized_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"expression\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"plain_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"anon_struct_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"array_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"atomic_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"channel_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"fixed_array_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"function_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"generic_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"map_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"multi_return_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"option_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"pointer_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"qualified_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"result_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"shared_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"thread_type\",\n          \"named\": true\n        },\n        {\n          \"type\": \"type_reference_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"wrong_pointer_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"pointer_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"qualified_type\",\n    \"named\": true,\n    \"fields\": {\n      \"module\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"reference_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"type_reference_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"range\",\n    \"named\": true,\n    \"fields\": {\n      \"end\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operator\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"..\",\n            \"named\": false\n          },\n          {\n            \"type\": \"...\",\n            \"named\": false\n          }\n        ]\n      },\n      \"start\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"range_clause\",\n    \"named\": true,\n    \"fields\": {\n      \"left\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"var_definition_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"right\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"range\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"raw_string_literal\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"receive_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"operand\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operator\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"<-\",\n            \"named\": false\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"receiver\",\n    \"named\": true,\n    \"fields\": {\n      \"mutability\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"mutability_modifiers\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"reference_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"result_propagation_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"result_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"return_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"expression_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"select_arm\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"block\",\n          \"named\": true\n        },\n        {\n          \"type\": \"select_arm_statement\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"select_arm_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"expression_list\",\n          \"named\": true\n        },\n        {\n          \"type\": \"send_statement\",\n          \"named\": true\n        },\n        {\n          \"type\": \"var_declaration\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"select_else_arn_clause\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"block\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"select_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"selected_variables\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"select_arm\",\n          \"named\": true\n        },\n        {\n          \"type\": \"select_else_arn_clause\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"selective_import_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"selector_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"field\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"compile_time_selector_expression\",\n            \"named\": true\n          },\n          {\n            \"type\": \"reference_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operand\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"send_statement\",\n    \"named\": true,\n    \"fields\": {\n      \"channel\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"value\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"shared_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"shebang\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"short_element_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"element\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"short_lambda\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"array_creation\",\n          \"named\": true\n        },\n        {\n          \"type\": \"as_type_cast_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"binary_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"call_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"dec_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"enum_fetch\",\n          \"named\": true\n        },\n        {\n          \"type\": \"fixed_array_creation\",\n          \"named\": true\n        },\n        {\n          \"type\": \"function_literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"go_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"in_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"inc_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"index_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"is_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"literal\",\n          \"named\": true\n        },\n        {\n          \"type\": \"option_propagation_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"or_block_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"parenthesized_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"pseudo_compile_time_identifier\",\n          \"named\": true\n        },\n        {\n          \"type\": \"receive_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"result_propagation_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"selector_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"slice_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"spawn_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"unary_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"signature\",\n    \"named\": true,\n    \"fields\": {\n      \"parameters\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"parameter_list\",\n            \"named\": true\n          },\n          {\n            \"type\": \"type_parameter_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"result\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"simple_statement\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"assignment_statement\",\n          \"named\": true\n        },\n        {\n          \"type\": \"expression_list\",\n          \"named\": true\n        },\n        {\n          \"type\": \"var_declaration\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"slice_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"operand\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"range\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"source_file\",\n    \"named\": true,\n    \"root\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"_statement\",\n          \"named\": true\n        },\n        {\n          \"type\": \"_top_level_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"import_list\",\n          \"named\": true\n        },\n        {\n          \"type\": \"module_clause\",\n          \"named\": true\n        },\n        {\n          \"type\": \"shebang\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"spawn_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"special_argument_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"spread_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"sql_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"static_method_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      },\n      \"body\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"block\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          },\n          {\n            \"type\": \"overridable_operator\",\n            \"named\": true\n          }\n        ]\n      },\n      \"signature\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"signature\",\n            \"named\": true\n          }\n        ]\n      },\n      \"static_receiver\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"static_receiver\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"static_receiver\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"reference_expression\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"string_interpolation\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"format_specifier\",\n          \"named\": true\n        },\n        {\n          \"type\": \"interpolation_closing\",\n          \"named\": true\n        },\n        {\n          \"type\": \"interpolation_expression\",\n          \"named\": true\n        },\n        {\n          \"type\": \"interpolation_opening\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"struct_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attributes\",\n            \"named\": true\n          }\n        ]\n      },\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"implements\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"implements_clause\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": true,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"struct_field_declaration\",\n          \"named\": true\n        },\n        {\n          \"type\": \"struct_field_scope\",\n          \"named\": true\n        },\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"struct_field_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"attributes\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"attribute\",\n            \"named\": true\n          }\n        ]\n      },\n      \"default_value\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"embedded_definition\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"struct_field_scope\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"sum_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"thread_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"type_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"generic_parameters\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"generic_parameters\",\n            \"named\": true\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          },\n          {\n            \"type\": \"sum_type\",\n            \"named\": true\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"visibility_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"type_initializer\",\n    \"named\": true,\n    \"fields\": {\n      \"body\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"type_initializer_body\",\n            \"named\": true\n          }\n        ]\n      },\n      \"type\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"type_initializer_body\",\n    \"named\": true,\n    \"fields\": {\n      \"element_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"element_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"short_element_list\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"short_element_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"type_parameter_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"type\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"plain_type\",\n            \"named\": true\n          }\n        ]\n      },\n      \"variadic\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"...\",\n            \"named\": false\n          }\n        ]\n      }\n    },\n    \"children\": {\n      \"multiple\": false,\n      \"required\": false,\n      \"types\": [\n        {\n          \"type\": \"mutability_modifiers\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"type_parameter_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"type_parameter_declaration\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"type_parameters\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"type_reference_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"identifier\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"unary_expression\",\n    \"named\": true,\n    \"fields\": {\n      \"operand\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"_expression\",\n            \"named\": true\n          }\n        ]\n      },\n      \"operator\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"!\",\n            \"named\": false\n          },\n          {\n            \"type\": \"&\",\n            \"named\": false\n          },\n          {\n            \"type\": \"*\",\n            \"named\": false\n          },\n          {\n            \"type\": \"+\",\n            \"named\": false\n          },\n          {\n            \"type\": \"-\",\n            \"named\": false\n          },\n          {\n            \"type\": \"^\",\n            \"named\": false\n          },\n          {\n            \"type\": \"~\",\n            \"named\": false\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"unsafe_expression\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"block\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"value_attribute\",\n    \"named\": true,\n    \"fields\": {\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"reference_expression\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"var_declaration\",\n    \"named\": true,\n    \"fields\": {\n      \"expression_list\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          }\n        ]\n      },\n      \"var_list\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"expression_list\",\n            \"named\": true\n          },\n          {\n            \"type\": \"identifier_list\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"var_definition\",\n    \"named\": true,\n    \"fields\": {\n      \"modifiers\": {\n        \"multiple\": false,\n        \"required\": false,\n        \"types\": [\n          {\n            \"type\": \"mut\",\n            \"named\": false\n          }\n        ]\n      },\n      \"name\": {\n        \"multiple\": false,\n        \"required\": true,\n        \"types\": [\n          {\n            \"type\": \"identifier\",\n            \"named\": true\n          }\n        ]\n      }\n    }\n  },\n  {\n    \"type\": \"var_definition_list\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": true,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"var_definition\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"variadic_parameter\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"visibility_modifiers\",\n    \"named\": true,\n    \"fields\": {}\n  },\n  {\n    \"type\": \"wrong_pointer_type\",\n    \"named\": true,\n    \"fields\": {},\n    \"children\": {\n      \"multiple\": false,\n      \"required\": true,\n      \"types\": [\n        {\n          \"type\": \"plain_type\",\n          \"named\": true\n        }\n      ]\n    }\n  },\n  {\n    \"type\": \"\\n\",\n    \"named\": false\n  },\n  {\n    \"type\": \"\\r\",\n    \"named\": false\n  },\n  {\n    \"type\": \"\\r\\n\",\n    \"named\": false\n  },\n  {\n    \"type\": \"!\",\n    \"named\": false\n  },\n  {\n    \"type\": \"!=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"!in\",\n    \"named\": false\n  },\n  {\n    \"type\": \"!is\",\n    \"named\": false\n  },\n  {\n    \"type\": \"\\\"\",\n    \"named\": false\n  },\n  {\n    \"type\": \"#\",\n    \"named\": false\n  },\n  {\n    \"type\": \"#!\",\n    \"named\": false\n  },\n  {\n    \"type\": \"#[\",\n    \"named\": false\n  },\n  {\n    \"type\": \"$\",\n    \"named\": false\n  },\n  {\n    \"type\": \"$(\",\n    \"named\": false\n  },\n  {\n    \"type\": \"$else\",\n    \"named\": false\n  },\n  {\n    \"type\": \"$for\",\n    \"named\": false\n  },\n  {\n    \"type\": \"$if\",\n    \"named\": false\n  },\n  {\n    \"type\": \"%\",\n    \"named\": false\n  },\n  {\n    \"type\": \"%=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"&\",\n    \"named\": false\n  },\n  {\n    \"type\": \"&&\",\n    \"named\": false\n  },\n  {\n    \"type\": \"&=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"&^\",\n    \"named\": false\n  },\n  {\n    \"type\": \"&^=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"'\",\n    \"named\": false\n  },\n  {\n    \"type\": \"(\",\n    \"named\": false\n  },\n  {\n    \"type\": \")\",\n    \"named\": false\n  },\n  {\n    \"type\": \"*\",\n    \"named\": false\n  },\n  {\n    \"type\": \"*/\",\n    \"named\": false\n  },\n  {\n    \"type\": \"*=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"+\",\n    \"named\": false\n  },\n  {\n    \"type\": \"++\",\n    \"named\": false\n  },\n  {\n    \"type\": \"+=\",\n    \"named\": false\n  },\n  {\n    \"type\": \",\",\n    \"named\": false\n  },\n  {\n    \"type\": \"-\",\n    \"named\": false\n  },\n  {\n    \"type\": \"--\",\n    \"named\": false\n  },\n  {\n    \"type\": \"-=\",\n    \"named\": false\n  },\n  {\n    \"type\": \".\",\n    \"named\": false\n  },\n  {\n    \"type\": \"..\",\n    \"named\": false\n  },\n  {\n    \"type\": \"...\",\n    \"named\": false\n  },\n  {\n    \"type\": \"/\",\n    \"named\": false\n  },\n  {\n    \"type\": \"/*\",\n    \"named\": false\n  },\n  {\n    \"type\": \"//\",\n    \"named\": false\n  },\n  {\n    \"type\": \"/=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"0\",\n    \"named\": false\n  },\n  {\n    \"type\": \":\",\n    \"named\": false\n  },\n  {\n    \"type\": \":=\",\n    \"named\": false\n  },\n  {\n    \"type\": \";\",\n    \"named\": false\n  },\n  {\n    \"type\": \"<\",\n    \"named\": false\n  },\n  {\n    \"type\": \"<-\",\n    \"named\": false\n  },\n  {\n    \"type\": \"<<\",\n    \"named\": false\n  },\n  {\n    \"type\": \"<<=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"<=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"==\",\n    \"named\": false\n  },\n  {\n    \"type\": \">\",\n    \"named\": false\n  },\n  {\n    \"type\": \">=\",\n    \"named\": false\n  },\n  {\n    \"type\": \">>\",\n    \"named\": false\n  },\n  {\n    \"type\": \">>=\",\n    \"named\": false\n  },\n  {\n    \"type\": \">>>\",\n    \"named\": false\n  },\n  {\n    \"type\": \">>>=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"?\",\n    \"named\": false\n  },\n  {\n    \"type\": \"?.\",\n    \"named\": false\n  },\n  {\n    \"type\": \"@[\",\n    \"named\": false\n  },\n  {\n    \"type\": \"[\",\n    \"named\": false\n  },\n  {\n    \"type\": \"]\",\n    \"named\": false\n  },\n  {\n    \"type\": \"^\",\n    \"named\": false\n  },\n  {\n    \"type\": \"^=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"__global\",\n    \"named\": false\n  },\n  {\n    \"type\": \"as\",\n    \"named\": false\n  },\n  {\n    \"type\": \"asm\",\n    \"named\": false\n  },\n  {\n    \"type\": \"assert\",\n    \"named\": false\n  },\n  {\n    \"type\": \"atomic\",\n    \"named\": false\n  },\n  {\n    \"type\": \"break\",\n    \"named\": false\n  },\n  {\n    \"type\": \"c\\\"\",\n    \"named\": false\n  },\n  {\n    \"type\": \"c'\",\n    \"named\": false\n  },\n  {\n    \"type\": \"chan\",\n    \"named\": false\n  },\n  {\n    \"type\": \"const\",\n    \"named\": false\n  },\n  {\n    \"type\": \"continue\",\n    \"named\": false\n  },\n  {\n    \"type\": \"defer\",\n    \"named\": false\n  },\n  {\n    \"type\": \"else\",\n    \"named\": false\n  },\n  {\n    \"type\": \"enum\",\n    \"named\": false\n  },\n  {\n    \"type\": \"escape_sequence\",\n    \"named\": true\n  },\n  {\n    \"type\": \"false\",\n    \"named\": true\n  },\n  {\n    \"type\": \"float_literal\",\n    \"named\": true\n  },\n  {\n    \"type\": \"fn\",\n    \"named\": false\n  },\n  {\n    \"type\": \"for\",\n    \"named\": false\n  },\n  {\n    \"type\": \"go\",\n    \"named\": false\n  },\n  {\n    \"type\": \"goto\",\n    \"named\": false\n  },\n  {\n    \"type\": \"identifier\",\n    \"named\": true\n  },\n  {\n    \"type\": \"if\",\n    \"named\": false\n  },\n  {\n    \"type\": \"implements\",\n    \"named\": false\n  },\n  {\n    \"type\": \"import\",\n    \"named\": false\n  },\n  {\n    \"type\": \"in\",\n    \"named\": false\n  },\n  {\n    \"type\": \"int_literal\",\n    \"named\": true\n  },\n  {\n    \"type\": \"interface\",\n    \"named\": false\n  },\n  {\n    \"type\": \"interpolation_closing\",\n    \"named\": true\n  },\n  {\n    \"type\": \"interpolation_opening\",\n    \"named\": true\n  },\n  {\n    \"type\": \"is\",\n    \"named\": false\n  },\n  {\n    \"type\": \"json.decode\",\n    \"named\": false\n  },\n  {\n    \"type\": \"lock\",\n    \"named\": false\n  },\n  {\n    \"type\": \"map[\",\n    \"named\": false\n  },\n  {\n    \"type\": \"match\",\n    \"named\": false\n  },\n  {\n    \"type\": \"module\",\n    \"named\": false\n  },\n  {\n    \"type\": \"mut\",\n    \"named\": false\n  },\n  {\n    \"type\": \"nil\",\n    \"named\": true\n  },\n  {\n    \"type\": \"none\",\n    \"named\": true\n  },\n  {\n    \"type\": \"or\",\n    \"named\": false\n  },\n  {\n    \"type\": \"pseudo_compile_time_identifier\",\n    \"named\": true\n  },\n  {\n    \"type\": \"pub\",\n    \"named\": false\n  },\n  {\n    \"type\": \"r\\\"\",\n    \"named\": false\n  },\n  {\n    \"type\": \"r'\",\n    \"named\": false\n  },\n  {\n    \"type\": \"return\",\n    \"named\": false\n  },\n  {\n    \"type\": \"rlock\",\n    \"named\": false\n  },\n  {\n    \"type\": \"rune_literal\",\n    \"named\": true\n  },\n  {\n    \"type\": \"select\",\n    \"named\": false\n  },\n  {\n    \"type\": \"shared\",\n    \"named\": false\n  },\n  {\n    \"type\": \"spawn\",\n    \"named\": false\n  },\n  {\n    \"type\": \"sql\",\n    \"named\": false\n  },\n  {\n    \"type\": \"static\",\n    \"named\": false\n  },\n  {\n    \"type\": \"struct\",\n    \"named\": false\n  },\n  {\n    \"type\": \"thread\",\n    \"named\": false\n  },\n  {\n    \"type\": \"true\",\n    \"named\": true\n  },\n  {\n    \"type\": \"type\",\n    \"named\": false\n  },\n  {\n    \"type\": \"union\",\n    \"named\": false\n  },\n  {\n    \"type\": \"unsafe\",\n    \"named\": false\n  },\n  {\n    \"type\": \"volatile\",\n    \"named\": false\n  },\n  {\n    \"type\": \"{\",\n    \"named\": false\n  },\n  {\n    \"type\": \"|\",\n    \"named\": false\n  },\n  {\n    \"type\": \"|=\",\n    \"named\": false\n  },\n  {\n    \"type\": \"||\",\n    \"named\": false\n  },\n  {\n    \"type\": \"}\",\n    \"named\": false\n  },\n  {\n    \"type\": \"~\",\n    \"named\": false\n  }\n]"
  },
  {
    "path": "tree_sitter_v/src/tree_sitter/alloc.h",
    "content": "#ifndef TREE_SITTER_ALLOC_H_\n#define TREE_SITTER_ALLOC_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n// Allow clients to override allocation functions\n#ifdef TREE_SITTER_REUSE_ALLOCATOR\n\nextern void *(*ts_current_malloc)(size_t size);\nextern void *(*ts_current_calloc)(size_t count, size_t size);\nextern void *(*ts_current_realloc)(void *ptr, size_t size);\nextern void (*ts_current_free)(void *ptr);\n\n#ifndef ts_malloc\n#define ts_malloc  ts_current_malloc\n#endif\n#ifndef ts_calloc\n#define ts_calloc  ts_current_calloc\n#endif\n#ifndef ts_realloc\n#define ts_realloc ts_current_realloc\n#endif\n#ifndef ts_free\n#define ts_free    ts_current_free\n#endif\n\n#else\n\n#ifndef ts_malloc\n#define ts_malloc  malloc\n#endif\n#ifndef ts_calloc\n#define ts_calloc  calloc\n#endif\n#ifndef ts_realloc\n#define ts_realloc realloc\n#endif\n#ifndef ts_free\n#define ts_free    free\n#endif\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // TREE_SITTER_ALLOC_H_\n"
  },
  {
    "path": "tree_sitter_v/src/tree_sitter/array.h",
    "content": "#ifndef TREE_SITTER_ARRAY_H_\n#define TREE_SITTER_ARRAY_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"./alloc.h\"\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4101)\n#elif defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunused-variable\"\n#endif\n\n#define Array(T)       \\\n  struct {             \\\n    T *contents;       \\\n    uint32_t size;     \\\n    uint32_t capacity; \\\n  }\n\n/// Initialize an array.\n#define array_init(self) \\\n  ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)\n\n/// Create an empty array.\n#define array_new() \\\n  { NULL, 0, 0 }\n\n/// Get a pointer to the element at a given `index` in the array.\n#define array_get(self, _index) \\\n  (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])\n\n/// Get a pointer to the first element in the array.\n#define array_front(self) array_get(self, 0)\n\n/// Get a pointer to the last element in the array.\n#define array_back(self) array_get(self, (self)->size - 1)\n\n/// Clear the array, setting its size to zero. Note that this does not free any\n/// memory allocated for the array's contents.\n#define array_clear(self) ((self)->size = 0)\n\n/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is\n/// less than the array's current capacity, this function has no effect.\n#define array_reserve(self, new_capacity) \\\n  _array__reserve((Array *)(self), array_elem_size(self), new_capacity)\n\n/// Free any memory allocated for this array. Note that this does not free any\n/// memory allocated for the array's contents.\n#define array_delete(self) _array__delete((Array *)(self))\n\n/// Push a new `element` onto the end of the array.\n#define array_push(self, element)                            \\\n  (_array__grow((Array *)(self), 1, array_elem_size(self)), \\\n   (self)->contents[(self)->size++] = (element))\n\n/// Increase the array's size by `count` elements.\n/// New elements are zero-initialized.\n#define array_grow_by(self, count) \\\n  do { \\\n    if ((count) == 0) break; \\\n    _array__grow((Array *)(self), count, array_elem_size(self)); \\\n    memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \\\n    (self)->size += (count); \\\n  } while (0)\n\n/// Append all elements from one array to the end of another.\n#define array_push_all(self, other)                                       \\\n  array_extend((self), (other)->size, (other)->contents)\n\n/// Append `count` elements to the end of the array, reading their values from the\n/// `contents` pointer.\n#define array_extend(self, count, contents)                    \\\n  _array__splice(                                               \\\n    (Array *)(self), array_elem_size(self), (self)->size, \\\n    0, count,  contents                                        \\\n  )\n\n/// Remove `old_count` elements from the array starting at the given `index`. At\n/// the same index, insert `new_count` new elements, reading their values from the\n/// `new_contents` pointer.\n#define array_splice(self, _index, old_count, new_count, new_contents)  \\\n  _array__splice(                                                       \\\n    (Array *)(self), array_elem_size(self), _index,                \\\n    old_count, new_count, new_contents                                 \\\n  )\n\n/// Insert one `element` into the array at the given `index`.\n#define array_insert(self, _index, element) \\\n  _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))\n\n/// Remove one element from the array at the given `index`.\n#define array_erase(self, _index) \\\n  _array__erase((Array *)(self), array_elem_size(self), _index)\n\n/// Pop the last element off the array, returning the element by value.\n#define array_pop(self) ((self)->contents[--(self)->size])\n\n/// Assign the contents of one array to another, reallocating if necessary.\n#define array_assign(self, other) \\\n  _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))\n\n/// Swap one array with another\n#define array_swap(self, other) \\\n  _array__swap((Array *)(self), (Array *)(other))\n\n/// Get the size of the array contents\n#define array_elem_size(self) (sizeof *(self)->contents)\n\n/// Search a sorted array for a given `needle` value, using the given `compare`\n/// callback to determine the order.\n///\n/// If an existing element is found to be equal to `needle`, then the `index`\n/// out-parameter is set to the existing value's index, and the `exists`\n/// out-parameter is set to true. Otherwise, `index` is set to an index where\n/// `needle` should be inserted in order to preserve the sorting, and `exists`\n/// is set to false.\n#define array_search_sorted_with(self, compare, needle, _index, _exists) \\\n  _array__search_sorted(self, 0, compare, , needle, _index, _exists)\n\n/// Search a sorted array for a given `needle` value, using integer comparisons\n/// of a given struct field (specified with a leading dot) to determine the order.\n///\n/// See also `array_search_sorted_with`.\n#define array_search_sorted_by(self, field, needle, _index, _exists) \\\n  _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)\n\n/// Insert a given `value` into a sorted array, using the given `compare`\n/// callback to determine the order.\n#define array_insert_sorted_with(self, compare, value) \\\n  do { \\\n    unsigned _index, _exists; \\\n    array_search_sorted_with(self, compare, &(value), &_index, &_exists); \\\n    if (!_exists) array_insert(self, _index, value); \\\n  } while (0)\n\n/// Insert a given `value` into a sorted array, using integer comparisons of\n/// a given struct field (specified with a leading dot) to determine the order.\n///\n/// See also `array_search_sorted_by`.\n#define array_insert_sorted_by(self, field, value) \\\n  do { \\\n    unsigned _index, _exists; \\\n    array_search_sorted_by(self, field, (value) field, &_index, &_exists); \\\n    if (!_exists) array_insert(self, _index, value); \\\n  } while (0)\n\n// Private\n\ntypedef Array(void) Array;\n\n/// This is not what you're looking for, see `array_delete`.\nstatic inline void _array__delete(Array *self) {\n  if (self->contents) {\n    ts_free(self->contents);\n    self->contents = NULL;\n    self->size = 0;\n    self->capacity = 0;\n  }\n}\n\n/// This is not what you're looking for, see `array_erase`.\nstatic inline void _array__erase(Array *self, size_t element_size,\n                                uint32_t index) {\n  assert(index < self->size);\n  char *contents = (char *)self->contents;\n  memmove(contents + index * element_size, contents + (index + 1) * element_size,\n          (self->size - index - 1) * element_size);\n  self->size--;\n}\n\n/// This is not what you're looking for, see `array_reserve`.\nstatic inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {\n  if (new_capacity > self->capacity) {\n    if (self->contents) {\n      self->contents = ts_realloc(self->contents, new_capacity * element_size);\n    } else {\n      self->contents = ts_malloc(new_capacity * element_size);\n    }\n    self->capacity = new_capacity;\n  }\n}\n\n/// This is not what you're looking for, see `array_assign`.\nstatic inline void _array__assign(Array *self, const Array *other, size_t element_size) {\n  _array__reserve(self, element_size, other->size);\n  self->size = other->size;\n  memcpy(self->contents, other->contents, self->size * element_size);\n}\n\n/// This is not what you're looking for, see `array_swap`.\nstatic inline void _array__swap(Array *self, Array *other) {\n  Array swap = *other;\n  *other = *self;\n  *self = swap;\n}\n\n/// This is not what you're looking for, see `array_push` or `array_grow_by`.\nstatic inline void _array__grow(Array *self, uint32_t count, size_t element_size) {\n  uint32_t new_size = self->size + count;\n  if (new_size > self->capacity) {\n    uint32_t new_capacity = self->capacity * 2;\n    if (new_capacity < 8) new_capacity = 8;\n    if (new_capacity < new_size) new_capacity = new_size;\n    _array__reserve(self, element_size, new_capacity);\n  }\n}\n\n/// This is not what you're looking for, see `array_splice`.\nstatic inline void _array__splice(Array *self, size_t element_size,\n                                 uint32_t index, uint32_t old_count,\n                                 uint32_t new_count, const void *elements) {\n  uint32_t new_size = self->size + new_count - old_count;\n  uint32_t old_end = index + old_count;\n  uint32_t new_end = index + new_count;\n  assert(old_end <= self->size);\n\n  _array__reserve(self, element_size, new_size);\n\n  char *contents = (char *)self->contents;\n  if (self->size > old_end) {\n    memmove(\n      contents + new_end * element_size,\n      contents + old_end * element_size,\n      (self->size - old_end) * element_size\n    );\n  }\n  if (new_count > 0) {\n    if (elements) {\n      memcpy(\n        (contents + index * element_size),\n        elements,\n        new_count * element_size\n      );\n    } else {\n      memset(\n        (contents + index * element_size),\n        0,\n        new_count * element_size\n      );\n    }\n  }\n  self->size += new_count - old_count;\n}\n\n/// A binary search routine, based on Rust's `std::slice::binary_search_by`.\n/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.\n#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \\\n  do { \\\n    *(_index) = start; \\\n    *(_exists) = false; \\\n    uint32_t size = (self)->size - *(_index); \\\n    if (size == 0) break; \\\n    int comparison; \\\n    while (size > 1) { \\\n      uint32_t half_size = size / 2; \\\n      uint32_t mid_index = *(_index) + half_size; \\\n      comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \\\n      if (comparison <= 0) *(_index) = mid_index; \\\n      size -= half_size; \\\n    } \\\n    comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \\\n    if (comparison == 0) *(_exists) = true; \\\n    else if (comparison < 0) *(_index) += 1; \\\n  } while (0)\n\n/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)\n/// parameter by reference in order to work with the generic sorting function above.\n#define _compare_int(a, b) ((int)*(a) - (int)(b))\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#elif defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // TREE_SITTER_ARRAY_H_\n"
  },
  {
    "path": "tree_sitter_v/src/tree_sitter/parser.h",
    "content": "#ifndef TREE_SITTER_PARSER_H_\n#define TREE_SITTER_PARSER_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#define ts_builtin_sym_error ((TSSymbol)-1)\n#define ts_builtin_sym_end 0\n#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024\n\n#ifndef TREE_SITTER_API_H_\ntypedef uint16_t TSStateId;\ntypedef uint16_t TSSymbol;\ntypedef uint16_t TSFieldId;\ntypedef struct TSLanguage TSLanguage;\ntypedef struct TSLanguageMetadata {\n  uint8_t major_version;\n  uint8_t minor_version;\n  uint8_t patch_version;\n} TSLanguageMetadata;\n#endif\n\ntypedef struct {\n  TSFieldId field_id;\n  uint8_t child_index;\n  bool inherited;\n} TSFieldMapEntry;\n\n// Used to index the field and supertype maps.\ntypedef struct {\n  uint16_t index;\n  uint16_t length;\n} TSMapSlice;\n\ntypedef struct {\n  bool visible;\n  bool named;\n  bool supertype;\n} TSSymbolMetadata;\n\ntypedef struct TSLexer TSLexer;\n\nstruct TSLexer {\n  int32_t lookahead;\n  TSSymbol result_symbol;\n  void (*advance)(TSLexer *, bool);\n  void (*mark_end)(TSLexer *);\n  uint32_t (*get_column)(TSLexer *);\n  bool (*is_at_included_range_start)(const TSLexer *);\n  bool (*eof)(const TSLexer *);\n  void (*log)(const TSLexer *, const char *, ...);\n};\n\ntypedef enum {\n  TSParseActionTypeShift,\n  TSParseActionTypeReduce,\n  TSParseActionTypeAccept,\n  TSParseActionTypeRecover,\n} TSParseActionType;\n\ntypedef union {\n  struct {\n    uint8_t type;\n    TSStateId state;\n    bool extra;\n    bool repetition;\n  } shift;\n  struct {\n    uint8_t type;\n    uint8_t child_count;\n    TSSymbol symbol;\n    int16_t dynamic_precedence;\n    uint16_t production_id;\n  } reduce;\n  uint8_t type;\n} TSParseAction;\n\ntypedef struct {\n  uint16_t lex_state;\n  uint16_t external_lex_state;\n} TSLexMode;\n\ntypedef struct {\n  uint16_t lex_state;\n  uint16_t external_lex_state;\n  uint16_t reserved_word_set_id;\n} TSLexerMode;\n\ntypedef union {\n  TSParseAction action;\n  struct {\n    uint8_t count;\n    bool reusable;\n  } entry;\n} TSParseActionEntry;\n\ntypedef struct {\n  int32_t start;\n  int32_t end;\n} TSCharacterRange;\n\nstruct TSLanguage {\n  uint32_t abi_version;\n  uint32_t symbol_count;\n  uint32_t alias_count;\n  uint32_t token_count;\n  uint32_t external_token_count;\n  uint32_t state_count;\n  uint32_t large_state_count;\n  uint32_t production_id_count;\n  uint32_t field_count;\n  uint16_t max_alias_sequence_length;\n  const uint16_t *parse_table;\n  const uint16_t *small_parse_table;\n  const uint32_t *small_parse_table_map;\n  const TSParseActionEntry *parse_actions;\n  const char * const *symbol_names;\n  const char * const *field_names;\n  const TSMapSlice *field_map_slices;\n  const TSFieldMapEntry *field_map_entries;\n  const TSSymbolMetadata *symbol_metadata;\n  const TSSymbol *public_symbol_map;\n  const uint16_t *alias_map;\n  const TSSymbol *alias_sequences;\n  const TSLexerMode *lex_modes;\n  bool (*lex_fn)(TSLexer *, TSStateId);\n  bool (*keyword_lex_fn)(TSLexer *, TSStateId);\n  TSSymbol keyword_capture_token;\n  struct {\n    const bool *states;\n    const TSSymbol *symbol_map;\n    void *(*create)(void);\n    void (*destroy)(void *);\n    bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);\n    unsigned (*serialize)(void *, char *);\n    void (*deserialize)(void *, const char *, unsigned);\n  } external_scanner;\n  const TSStateId *primary_state_ids;\n  const char *name;\n  const TSSymbol *reserved_words;\n  uint16_t max_reserved_word_set_size;\n  uint32_t supertype_count;\n  const TSSymbol *supertype_symbols;\n  const TSMapSlice *supertype_map_slices;\n  const TSSymbol *supertype_map_entries;\n  TSLanguageMetadata metadata;\n};\n\nstatic inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {\n  uint32_t index = 0;\n  uint32_t size = len - index;\n  while (size > 1) {\n    uint32_t half_size = size / 2;\n    uint32_t mid_index = index + half_size;\n    const TSCharacterRange *range = &ranges[mid_index];\n    if (lookahead >= range->start && lookahead <= range->end) {\n      return true;\n    } else if (lookahead > range->end) {\n      index = mid_index;\n    }\n    size -= half_size;\n  }\n  const TSCharacterRange *range = &ranges[index];\n  return (lookahead >= range->start && lookahead <= range->end);\n}\n\n/*\n *  Lexer Macros\n */\n\n#ifdef _MSC_VER\n#define UNUSED __pragma(warning(suppress : 4101))\n#else\n#define UNUSED __attribute__((unused))\n#endif\n\n#define START_LEXER()           \\\n  bool result = false;          \\\n  bool skip = false;            \\\n  UNUSED                        \\\n  bool eof = false;             \\\n  int32_t lookahead;            \\\n  goto start;                   \\\n  next_state:                   \\\n  lexer->advance(lexer, skip);  \\\n  start:                        \\\n  skip = false;                 \\\n  lookahead = lexer->lookahead;\n\n#define ADVANCE(state_value) \\\n  {                          \\\n    state = state_value;     \\\n    goto next_state;         \\\n  }\n\n#define ADVANCE_MAP(...)                                              \\\n  {                                                                   \\\n    static const uint16_t map[] = { __VA_ARGS__ };                    \\\n    for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) {  \\\n      if (map[i] == lookahead) {                                      \\\n        state = map[i + 1];                                           \\\n        goto next_state;                                              \\\n      }                                                               \\\n    }                                                                 \\\n  }\n\n#define SKIP(state_value) \\\n  {                       \\\n    skip = true;          \\\n    state = state_value;  \\\n    goto next_state;      \\\n  }\n\n#define ACCEPT_TOKEN(symbol_value)     \\\n  result = true;                       \\\n  lexer->result_symbol = symbol_value; \\\n  lexer->mark_end(lexer);\n\n#define END_STATE() return result;\n\n/*\n *  Parse Table Macros\n */\n\n#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)\n\n#define STATE(id) id\n\n#define ACTIONS(id) id\n\n#define SHIFT(state_value)            \\\n  {{                                  \\\n    .shift = {                        \\\n      .type = TSParseActionTypeShift, \\\n      .state = (state_value)          \\\n    }                                 \\\n  }}\n\n#define SHIFT_REPEAT(state_value)     \\\n  {{                                  \\\n    .shift = {                        \\\n      .type = TSParseActionTypeShift, \\\n      .state = (state_value),         \\\n      .repetition = true              \\\n    }                                 \\\n  }}\n\n#define SHIFT_EXTRA()                 \\\n  {{                                  \\\n    .shift = {                        \\\n      .type = TSParseActionTypeShift, \\\n      .extra = true                   \\\n    }                                 \\\n  }}\n\n#define REDUCE(symbol_name, children, precedence, prod_id) \\\n  {{                                                       \\\n    .reduce = {                                            \\\n      .type = TSParseActionTypeReduce,                     \\\n      .symbol = symbol_name,                               \\\n      .child_count = children,                             \\\n      .dynamic_precedence = precedence,                    \\\n      .production_id = prod_id                             \\\n    },                                                     \\\n  }}\n\n#define RECOVER()                    \\\n  {{                                 \\\n    .type = TSParseActionTypeRecover \\\n  }}\n\n#define ACCEPT_INPUT()              \\\n  {{                                \\\n    .type = TSParseActionTypeAccept \\\n  }}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  // TREE_SITTER_PARSER_H_\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/anon_struct.txt",
    "content": "================================================================================\nSimple anon struct\n================================================================================\nstruct Foo {\n    inner struct {\n        name string\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (anon_struct_type\n          (struct_field_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier)))))))))\n\n================================================================================\nAnon struct with modifiers\n================================================================================\nstruct Foo {\n    inner struct {\n    pub:\n        name string\n    mut:\n        age int\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (anon_struct_type\n          (struct_field_scope)\n          (struct_field_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (struct_field_scope)\n          (struct_field_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier)))))))))\n\n================================================================================\nAnon struct as param type\n================================================================================\nfn func(arg struct { foo string }) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (anon_struct_type\n              (struct_field_declaration\n                (identifier)\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))))))))\n    (block)))\n\n================================================================================\nAnon struct value with short element list\n================================================================================\na := struct { 'abc' }\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (anon_struct_value_expression\n          (short_element_list\n            (element\n              (literal\n                (interpreted_string_literal)))))))))\n\n================================================================================\nAnon struct value with keyed element list\n================================================================================\na := struct {\n    foo: 'abc'\n    bar: 'def'\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (anon_struct_value_expression\n          (element_list\n            (keyed_element\n              (field_name\n                (reference_expression\n                  (identifier)))\n              (literal\n                (interpreted_string_literal)))\n            (keyed_element\n              (field_name\n                (reference_expression\n                  (identifier)))\n              (literal\n                (interpreted_string_literal)))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/array_creation.txt",
    "content": "================================================================================\nSimple array creation\n================================================================================\n[1, 2, 3]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (array_creation\n      (literal\n        (int_literal))\n      (literal\n        (int_literal))\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline array creation\n================================================================================\n[\n    1,\n    2,\n    3\n]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (array_creation\n      (literal\n        (int_literal))\n      (literal\n        (int_literal))\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline array creation with trailing comma\n================================================================================\n[\n    1,\n    2,\n    3,\n]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (array_creation\n      (literal\n        (int_literal))\n      (literal\n        (int_literal))\n      (literal\n        (int_literal)))))\n\n================================================================================\nSimple array creation with trailing comma\n================================================================================\n[1, 2, 3, ]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (array_creation\n      (literal\n        (int_literal))\n      (literal\n        (int_literal))\n      (literal\n        (int_literal)))))\n\n================================================================================\nEmpty array creation\n================================================================================\n[]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (array_creation)))\n\n================================================================================\nFixed array creation\n================================================================================\n[1, 2, 3]!\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (fixed_array_creation\n      (literal\n        (int_literal))\n      (literal\n        (int_literal))\n      (literal\n        (int_literal)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/assert_statement.txt",
    "content": "================================================================================\nSimple assert statement\n================================================================================\nassert 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (assert_statement\n    (literal\n      (int_literal))))\n\n================================================================================\nSimple assert statement with condition\n================================================================================\nassert a > b\n--------------------------------------------------------------------------------\n\n(source_file\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))))\n\n================================================================================\nAssert statement with message\n================================================================================\nassert a > b, 'a should be greater than b'\nassert a > b, 'a' + 'should be greater than' + 'b'\nassert a > b, '${a} should be greater than ${b}'\nassert a > b, '${a} should' + 'be greater than ${b}'\nassert a > b, a.str()\nassert a > b, a.str() + b.str()\n--------------------------------------------------------------------------------\n\n(source_file\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (literal\n      (interpreted_string_literal)))\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (binary_expression\n      (binary_expression\n        (literal\n          (interpreted_string_literal))\n        (literal\n          (interpreted_string_literal)))\n      (literal\n        (interpreted_string_literal))))\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing)))))\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (binary_expression\n      (literal\n        (interpreted_string_literal\n          (string_interpolation\n            (interpolation_opening)\n            (interpolation_expression\n              (reference_expression\n                (identifier)))\n            (interpolation_closing))))\n      (literal\n        (interpreted_string_literal\n          (string_interpolation\n            (interpolation_opening)\n            (interpolation_expression\n              (reference_expression\n                (identifier)))\n            (interpolation_closing))))))\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (call_expression\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (argument_list)))\n  (assert_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))\n    (binary_expression\n      (call_expression\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))\n        (argument_list))\n      (call_expression\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))\n        (argument_list)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/attributes.txt",
    "content": "================================================================================\nSimple attribute\n================================================================================\n[name]\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)))\n\n================================================================================\nSimple attributes\n================================================================================\n[name]\n[name1]\n@[name2]\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)))\n\n================================================================================\nIf attribute\n================================================================================\n[if name]\n[if name1 ?]\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (if_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (if_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)))\n\n================================================================================\nLiteral attribute\n================================================================================\n['hello']\n[100]\n[true]\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (literal_attribute\n            (literal\n              (interpreted_string_literal)))))\n      (attribute\n        (attribute_expression\n          (literal_attribute\n            (literal\n              (int_literal)))))\n      (attribute\n        (attribute_expression\n          (literal_attribute\n            (literal\n              (true))))))\n    (identifier)))\n\n================================================================================\nKey value attribute\n================================================================================\n[key: value]\n[key: 'hello']\n@[key: 100]\n@[key: true]\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (key_value_attribute\n            (value_attribute\n              (reference_expression\n                (identifier)))\n            (identifier))))\n      (attribute\n        (attribute_expression\n          (key_value_attribute\n            (value_attribute\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal)))))\n      (attribute\n        (attribute_expression\n          (key_value_attribute\n            (value_attribute\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))))\n      (attribute\n        (attribute_expression\n          (key_value_attribute\n            (value_attribute\n              (reference_expression\n                (identifier)))\n            (literal\n              (true))))))\n    (identifier)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/bitshift_left.txt",
    "content": "================================================================================\nBitshift as expression\n================================================================================\na := 10 << 2\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (binary_expression\n          (literal\n            (int_literal))\n          (literal\n            (int_literal)))))))\n\n================================================================================\nBitshift as append statement\n================================================================================\narr << 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (append_statement\n    (reference_expression\n      (identifier))\n    (literal\n      (int_literal))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/call_expression.txt",
    "content": "================================================================================\nSimple call expression\n================================================================================\nfoo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list))))\n\n================================================================================\nSimple call expression with argument\n================================================================================\nfoo(100)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSimple call expression with Option propagation\n================================================================================\nfoo(100)?\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (option_propagation_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list\n          (argument\n            (literal\n              (int_literal))))))))\n\n================================================================================\nSimple call expression with Result propagation\n================================================================================\nfoo(100)!\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (result_propagation_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list\n          (argument\n            (literal\n              (int_literal))))))))\n\n================================================================================\nSimple call expression with or block\n================================================================================\nfoo(100) or { 100 }\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (or_block_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list\n          (argument\n            (literal\n              (int_literal)))))\n      (or_block\n        (block\n          (simple_statement\n            (literal\n              (int_literal))))))))\n\n================================================================================\nSimple call expression with mutable argument\n================================================================================\nfoo(mut name)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (mutable_expression\n            (mutability_modifiers)\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with arguments\n================================================================================\nfoo(100, 100, 200)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSimple call expression with arguments and trailing comma\n================================================================================\nfoo(100, 100, 200, )\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSimple call expression with arguments on multiple lines\n================================================================================\nfoo(\n    100,\n    100,\n    200\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSimple call expression with arguments on multiple lines and trailing comma\n================================================================================\nfoo(\n    100,\n    100,\n    200,\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSimple call expression with last unpacking parameter\n================================================================================\nfoo(100, 100, ...[1, 2, 3])\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (literal\n            (int_literal)))\n        (argument\n          (spread_expression\n            (array_creation\n              (literal\n                (int_literal))\n              (literal\n                (int_literal))\n              (literal\n                (int_literal)))))))))\n\n================================================================================\nSimple call expression with key value argument\n================================================================================\nfoo(name: value)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with key value arguments\n================================================================================\nfoo(name: value, name2: value2, name3: value3)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with plain and key value arguments\n================================================================================\nfoo(plain, plain2, name: value, name2: value2, name3: value3)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (reference_expression\n            (identifier)))\n        (argument\n          (reference_expression\n            (identifier)))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with key value arguments on multiple lines\n================================================================================\nfoo(\n    name: value,\n    name2: value2,\n    name3: value3\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with key value arguments on multiple lines without commas\n================================================================================\nfoo(\n    name: value\n    name2: value2\n    name3: value3\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple call expression with key value arguments on multiple lines without commas with plain arg\n================================================================================\nfoo(\n    plain,\n    name: value\n    name2: value2\n    name3: value3\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (reference_expression\n            (identifier)))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))\n        (argument\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nGeneric function call with type parameter\n================================================================================\nfoo[int]()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (type_parameters\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (argument_list))))\n\n================================================================================\nGeneric function call with several type parameters\n================================================================================\nfoo[int, string]()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (type_parameters\n        (plain_type\n          (type_reference_expression\n            (identifier)))\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (argument_list))))\n\n================================================================================\nQualified call expression\n================================================================================\nbar.foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (argument_list))))\n\n================================================================================\nQualified call expression with two selectors\n================================================================================\nbar.name.foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))\n        (reference_expression\n          (identifier)))\n      (argument_list))))\n\n================================================================================\nQualified call expression with index expression\n================================================================================\nbar.name[0].foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (index_expression\n          (selector_expression\n            (reference_expression\n              (identifier))\n            (reference_expression\n              (identifier)))\n          (literal\n            (int_literal)))\n        (reference_expression\n          (identifier)))\n      (argument_list))))\n\n================================================================================\nQualified call expression with call expression\n================================================================================\nbar.name().foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (call_expression\n          (selector_expression\n            (reference_expression\n              (identifier))\n            (reference_expression\n              (identifier)))\n          (argument_list))\n        (reference_expression\n          (identifier)))\n      (argument_list))))\n\n================================================================================\nCall expression with ...\n================================================================================\nfoo(...name)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (spread_expression\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nCall short lambda\n================================================================================\nfoo(|| println(''))\nfoo(|a| println(a))\nfoo(|a, b| println('${a}${b}'))\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (short_lambda\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (literal\n                  (interpreted_string_literal)))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (short_lambda\n          (reference_expression\n            (identifier))\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (reference_expression\n                  (identifier)))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (short_lambda\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (literal\n                  (interpreted_string_literal\n                    (string_interpolation\n                      (interpolation_opening)\n                      (interpolation_expression\n                        (reference_expression\n                          (identifier)))\n                      (interpolation_closing))\n                    (string_interpolation\n                      (interpolation_opening)\n                      (interpolation_expression\n                        (reference_expression\n                          (identifier)))\n                      (interpolation_closing))))))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/channels.txt",
    "content": "================================================================================\nReceive expression\n================================================================================\ncache = <-cache_chan\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (assignment_statement\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (receive_expression\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nReceive expression with propagation\n================================================================================\ncache = <-cache_chan!\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (assignment_statement\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (receive_expression\n          (result_propagation_expression\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nReceive expression with or block\n================================================================================\ncache = <-cache_chan or { return }\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (assignment_statement\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (or_block_expression\n          (receive_expression\n            (reference_expression\n              (identifier)))\n          (or_block\n            (block\n              (return_statement))))))))\n\n================================================================================\nSend statement\n================================================================================\ncache <- cache_chan\n--------------------------------------------------------------------------------\n\n(source_file\n  (send_statement\n    (reference_expression\n      (identifier))\n    (reference_expression\n      (identifier))))\n\n================================================================================\nSend statement with propagation\n================================================================================\ncache <- cache_chan!\n--------------------------------------------------------------------------------\n\n(source_file\n  (send_statement\n    (reference_expression\n      (identifier))\n    (result_propagation_expression\n      (reference_expression\n        (identifier)))))\n\n================================================================================\nSend statement with or block\n================================================================================\ncache <- cache_chan or { return }\n--------------------------------------------------------------------------------\n\n(source_file\n  (send_statement\n    (reference_expression\n      (identifier))\n    (or_block_expression\n      (reference_expression\n        (identifier))\n      (or_block\n        (block\n          (return_statement))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/comments.txt",
    "content": "================================================================================\nEmpty comment\n================================================================================\n//\n/**/\n/***/\nmodule foo\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (block_comment)\n  (block_comment)\n  (module_clause\n    (identifier)))\n\n================================================================================\nLine comment\n================================================================================\n// Line comment\n// Line comment\nmodule foo\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (line_comment)\n  (module_clause\n    (identifier)))\n\n================================================================================\nMultiline comment\n================================================================================\n/*\n  Multiline comment\n  Multiline comment\n*/\n/*foo**/\nmodule foo\n/**foo*/\n/**foo**/\n--------------------------------------------------------------------------------\n\n(source_file\n  (block_comment)\n  (block_comment)\n  (module_clause\n    (identifier))\n  (block_comment)\n  (block_comment))\n\n================================================================================\nMultiline nested comment\n================================================================================\n/*\n  /* Nested with ending asterisks **/\n\n  /** Nested with starting asterisks */\n\n  /* Nested */\n*/\n// comment /* comment */\nmodule main\n/* Recuresively nested\n  > Level 1\n  /*\n    >> Level 2\n    /*\n\n      >>> Level 3\n      /* Nested */\n      <<<\n    */\n    <<\n  */\n  <\n*/\nfoo := 'abc'\n/**********************************************************************\n* Comment\n* /*** Nested ***/\n**********************************************************************/\n--------------------------------------------------------------------------------\n\n(source_file\n  (block_comment\n    (block_comment)\n    (block_comment)\n    (block_comment))\n  (line_comment)\n  (module_clause\n    (identifier))\n  (block_comment\n    (block_comment\n      (block_comment\n        (block_comment))))\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (literal\n          (interpreted_string_literal)))))\n  (block_comment\n    (block_comment)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/compile_time.txt",
    "content": "================================================================================\nCompile-time call expression\n================================================================================\n$embed_file('stubs/arrays.v', .zlib)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal)))\n        (argument\n          (enum_fetch\n            (reference_expression\n              (identifier))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/compile_time_selector_expression.txt",
    "content": "================================================================================\nSimple compile time selector\n================================================================================\nname.$(some)\nname.$(some.other)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (selector_expression\n      (reference_expression\n        (identifier))\n      (compile_time_selector_expression\n        (reference_expression\n          (identifier)))))\n  (simple_statement\n    (selector_expression\n      (reference_expression\n        (identifier))\n      (compile_time_selector_expression\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/const_declaration.txt",
    "content": "================================================================================\nSimple constant\n================================================================================\nconst name = 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nSeveral constants\n================================================================================\nconst name = 100\nconst other = 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal))))\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nSeveral constants with visibility modifiers\n================================================================================\nconst name = 100\npub const other = 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal))))\n  (const_declaration\n    (visibility_modifiers)\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline constant\n================================================================================\nconst (\n    name = 100\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline constant in one line with error\n================================================================================\nconst ( name = 100 )\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (ERROR\n      (const_definition\n        (identifier)\n        (literal\n          (int_literal))))))\n\n================================================================================\nMultiline constants\n================================================================================\nconst (\n    name = 100\n    other = 100\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline constants with visibility modifiers\n================================================================================\npub const (\n    name = 100\n    other = 100\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (visibility_modifiers)\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nSimple constant with attribute\n================================================================================\n[attr]\nconst name = 100\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline constants with attributes\n================================================================================\n[attr]\n[attr2]\npub const (\n    name = 100\n    other = 100\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (const_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (visibility_modifiers)\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (const_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/enum_declaration.txt",
    "content": "================================================================================\nSimple enum\n================================================================================\nenum Colors {\n    red\n    green\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier))\n    (enum_field_definition\n      (identifier))))\n\n================================================================================\nSimple empty enum\n================================================================================\nenum Colors {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)))\n\n================================================================================\nSimple public enum\n================================================================================\npub enum Colors {\n    red\n    green\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (visibility_modifiers)\n    (identifier)\n    (enum_field_definition\n      (identifier))\n    (enum_field_definition\n      (identifier))))\n\n================================================================================\nEnum with backed type\n================================================================================\nenum Colors as u8 {\n    red\n    green\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_backed_type\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (enum_field_definition\n      (identifier))\n    (enum_field_definition\n      (identifier))))\n\n================================================================================\nEnum with field value\n================================================================================\nenum Colors {\n    red\n    green = 2\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier))\n    (enum_field_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nEnum with fields values\n================================================================================\nenum Colors {\n    red = 1\n    green = 2\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (enum_field_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nEnum with fields bitshift values\n================================================================================\nenum Colors {\n    red = 1 << 1\n    green = 2 << 2\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier)\n      (binary_expression\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))\n    (enum_field_definition\n      (identifier)\n      (binary_expression\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))))\n\n================================================================================\nEnum with fields attributes\n================================================================================\nenum Colors {\n    red   [attr]\n    green [attr]\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier)\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (enum_field_definition\n      (identifier)\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nEnum with fields attributes and values\n================================================================================\nenum Colors {\n    red   = 1 [attr]\n    green = 2 [attr]\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (enum_declaration\n    (identifier)\n    (enum_field_definition\n      (identifier)\n      (literal\n        (int_literal))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (enum_field_definition\n      (identifier)\n      (literal\n        (int_literal))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/enum_fetch.txt",
    "content": "================================================================================\nSimple enum fetch\n================================================================================\n.red\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (enum_fetch\n      (reference_expression\n        (identifier)))))\n\n================================================================================\nSimple enum fetch in condition\n================================================================================\na == .red\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (enum_fetch\n        (reference_expression\n          (identifier))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/error_propagation.txt",
    "content": "================================================================================\nOr block\n================================================================================\nfoo or {}\nfoo() or {}\nfoo[1] or {}\nif true {} else {} or {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (or_block_expression\n      (reference_expression\n        (identifier))\n      (or_block\n        (block))))\n  (simple_statement\n    (or_block_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list))\n      (or_block\n        (block))))\n  (simple_statement\n    (or_block_expression\n      (index_expression\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal)))\n      (or_block\n        (block))))\n  (simple_statement\n    (or_block_expression\n      (if_expression\n        (literal\n          (true))\n        (block)\n        (else_branch\n          (block)))\n      (or_block\n        (block)))))\n\n================================================================================\n! propagation\n================================================================================\nfoo!\nfoo()!\nfoo[1]!\nif true {} else {}!\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (result_propagation_expression\n      (reference_expression\n        (identifier))))\n  (simple_statement\n    (result_propagation_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list))))\n  (simple_statement\n    (result_propagation_expression\n      (index_expression\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal)))))\n  (simple_statement\n    (result_propagation_expression\n      (if_expression\n        (literal\n          (true))\n        (block)\n        (else_branch\n          (block))))))\n\n================================================================================\n? propagation\n================================================================================\nfoo?\nfoo()?\nfoo[1]?\nif true {} else {}?\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (option_propagation_expression\n      (reference_expression\n        (identifier))))\n  (simple_statement\n    (option_propagation_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list))))\n  (simple_statement\n    (option_propagation_expression\n      (index_expression\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal)))))\n  (simple_statement\n    (option_propagation_expression\n      (if_expression\n        (literal\n          (true))\n        (block)\n        (else_branch\n          (block))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/expression_list.txt",
    "content": "================================================================================\nSimple expression list\n================================================================================\na, b\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (expression_list\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))))\n\n================================================================================\nExpression list inside if\n================================================================================\nif s.no_inner {\n    return '!'\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (block\n        (return_statement\n          (expression_list\n            (literal\n              (interpreted_string_literal))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/for_statement.txt",
    "content": "================================================================================\nSimple for in statement with two variables\n================================================================================\nfor _, v in a {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (range_clause\n      (var_definition_list\n        (var_definition\n          (identifier))\n        (var_definition\n          (identifier)))\n      (reference_expression\n        (identifier)))\n    (block)))\n\n================================================================================\nSimple for in statement with one variable\n================================================================================\nfor v in a {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (range_clause\n      (var_definition_list\n        (var_definition\n          (identifier)))\n      (reference_expression\n        (identifier)))\n    (block)))\n\n================================================================================\nSimple for in statement with range\n================================================================================\nfor i in 0 .. 10 {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (range_clause\n      (var_definition_list\n        (var_definition\n          (identifier)))\n      (range\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))\n    (block)))\n\n================================================================================\nSimple for is statement\n================================================================================\nfor v is a {\n}\nfor v !is Bar {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (is_clause\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (type_reference_expression\n            (identifier)))))\n    (block))\n  (for_statement\n    (is_clause\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (type_reference_expression\n            (identifier)))))\n    (block)))\n\n================================================================================\nSimple for mut is statement\n================================================================================\nfor mut v is Foo {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (is_clause\n      (mutability_modifiers)\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (type_reference_expression\n            (identifier)))))\n    (block)))\n\n================================================================================\nSimple C for statement\n================================================================================\nfor i := 0; i < 10; i++ {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (for_clause\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (literal\n              (int_literal)))))\n      (binary_expression\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal)))\n      (simple_statement\n        (inc_expression\n          (reference_expression\n            (identifier)))))\n    (block)))\n\n================================================================================\nSimple C for statement without last statement\n================================================================================\nfor i := 0; i < 10; {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (for_clause\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (literal\n              (int_literal)))))\n      (binary_expression\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal))))\n    (block)))\n\n================================================================================\nSimple C for statement without all statements\n================================================================================\nfor ;; {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (for_clause)\n    (block)))\n\n================================================================================\nSimple infinite for statement\n================================================================================\nfor {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (block)))\n\n================================================================================\nSimple condition for statement\n================================================================================\nfor a > 100 {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (for_statement\n    (binary_expression\n      (reference_expression\n        (identifier))\n      (literal\n        (int_literal)))\n    (block)))\n\n================================================================================\nCompile-time for statement\n================================================================================\n$for field in T.fields {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (compile_time_for_statement\n    (range_clause\n      (var_definition_list\n        (var_definition\n          (identifier)))\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier))))\n    (block)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/function_declaration.txt",
    "content": "================================================================================\nSimple function\n================================================================================\nfn foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple function with param\n================================================================================\nfn foo(param int) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with params\n================================================================================\nfn foo(param int, param2 string) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with params and trailing comma error\n================================================================================\nfn foo(param int, param2 string,) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (ERROR)))\n    (block)))\n\n================================================================================\nSimple function with params and last variadic param\n================================================================================\nfn foo(param int, param2 string, variadic ...[]string) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (array_type\n              (plain_type\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n\n================================================================================\nSimple function with mutable and shared params\n================================================================================\nfn foo(mut param int, shared param2 string) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with return type\n================================================================================\nfn foo(mut param int) string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (block)))\n\n================================================================================\nSimple function with Result return type\n================================================================================\nfn foo(mut param int) !string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (result_type\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with Option return type\n================================================================================\nfn foo(mut param int) ?string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (option_type\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with several return type\n================================================================================\nfn foo(mut param int) (string, int) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (multi_return_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with several return type and trailing comma\n================================================================================\nfn foo(mut param int) (string, int,) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (multi_return_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nSimple function with empty brace return type\n================================================================================\nfn foo(mut param int) () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (multi_return_type\n          (plain_type\n            (type_reference_expression\n              (MISSING identifier))))))\n    (block)))\n\n================================================================================\nSimple function with Result of several return type\n================================================================================\nfn foo(mut param int) !(string, int) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (result_type\n          (plain_type\n            (multi_return_type\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (plain_type\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n\n================================================================================\nSimple function with Option of several return type\n================================================================================\nfn foo(mut param int) ?(string, int) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (mutability_modifiers)\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (option_type\n          (plain_type\n            (multi_return_type\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (plain_type\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n\n================================================================================\nSimple function without block\n================================================================================\nfn foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))))\n\n================================================================================\nSimple C function without block\n================================================================================\nfn C.foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))))\n\n================================================================================\nSimple JS function without block\n================================================================================\nfn JS.foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))))\n\n================================================================================\nSimple function with attribute\n================================================================================\n[unsafe]\nfn foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression)))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple function with attributes\n================================================================================\n[unsafe]\n[other]\nfn foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple function with attributes and comment\n================================================================================\n// foo is a functions\n[unsafe]\n[other]\nfn foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (function_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple public function\n================================================================================\npub fn foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (visibility_modifiers)\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple generic function\n================================================================================\nfn foo[T]() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nGeneric function with several generic parameters\n================================================================================\nfn foo[T, U]() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nGeneric function with several generic parameters and trailing comma\n================================================================================\nfn foo[T, U, ]() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nAll in one function\n================================================================================\n// comment\n[unsafe; other]\npub fn C.foo[T, U, ](foo string, age ...int) !(int, string, ) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (function_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression)))\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (visibility_modifiers)\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (result_type\n          (plain_type\n            (multi_return_type\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (plain_type\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/function_literal.txt",
    "content": "================================================================================\nSimple function literal\n================================================================================\nfn () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list))\n      (block))))\n\n================================================================================\nSimple function literal with parameters\n================================================================================\nfn (a string, b int) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block))))\n\n================================================================================\nSimple function literal with return type\n================================================================================\nfn (a string, b int) Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier)))))\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block))))\n\n================================================================================\nSimple function literal with capture\n================================================================================\nfn [cap] () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (capture_list\n        (capture\n          (reference_expression\n            (identifier))))\n      (signature\n        (parameter_list))\n      (block))))\n\n================================================================================\nSimple function literal with captures\n================================================================================\nfn [cap, cap2] () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (capture_list\n        (capture\n          (reference_expression\n            (identifier)))\n        (capture\n          (reference_expression\n            (identifier))))\n      (signature\n        (parameter_list))\n      (block))))\n\n================================================================================\nSimple function literal with captures with trailing comma\n================================================================================\nfn [cap, cap2, ] () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (capture_list\n        (capture\n          (reference_expression\n            (identifier)))\n        (capture\n          (reference_expression\n            (identifier))))\n      (signature\n        (parameter_list))\n      (block))))\n\n================================================================================\nSimple function literal with mutable captures\n================================================================================\nfn [mut cap, cap2, shared cap3] () {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (capture_list\n        (capture\n          (mutability_modifiers)\n          (reference_expression\n            (identifier)))\n        (capture\n          (reference_expression\n            (identifier)))\n        (capture\n          (mutability_modifiers)\n          (reference_expression\n            (identifier))))\n      (signature\n        (parameter_list))\n      (block))))\n\n================================================================================\nSimple function literal with call\n================================================================================\nfn () {}()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (function_literal\n        (signature\n          (parameter_list))\n        (block))\n      (argument_list))))\n\n================================================================================\nSimple function literal as parameter\n================================================================================\napp.handle(fn (req &Req, res Res) ? {\n    return\n})\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (argument_list\n        (argument\n          (function_literal\n            (signature\n              (parameter_list\n                (parameter_declaration\n                  (identifier)\n                  (plain_type\n                    (pointer_type\n                      (plain_type\n                        (type_reference_expression\n                          (identifier))))))\n                (parameter_declaration\n                  (identifier)\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))\n              (plain_type\n                (option_type)))\n            (block\n              (return_statement))))))))\n\n================================================================================\nReal-world function literal\n================================================================================\nimport nedpals.vex.ctx\nimport time\nimport context\nimport picohttpparser\n\npub struct Config {\n\tcb           fn (voidptr, picohttpparser.Request, mut picohttpparser.Response)\n\terr_cb       fn (voidptr, picohttpparser.Request, mut picohttpparser.Response, IError) = default_err_cb\n\tuser_data    voidptr = unsafe { nil }\n\ttimeout_secs int     = 8\n\tmax_headers  int     = 100\n}\n\nfn main() {\n\ta := fn (a i64) i64 {\n\t\treturn 100\n\t}(100)\n\n\tif ctx.err() is none {\n\t\tgo fn (mut ctx TimerContext, dur time.Duration) {\n\t\t\tctx.cancel(true, deadline_exceeded)\n\t\t}(mut ctx, dur)\n\t}\n\n\tcancel_fn := fn [mut ctx] () {\n\t\tctx.cancel(true, canceled)\n\t}\n}\n\nfn test_with_value() {\n\tf := fn (ctx context.Context, key context.Key) &Value {\n\t\tif value := ctx.value(key) {\n\t\t\tmatch value {\n\t\t\t\tValue {\n\t\t\t\t\treturn value\n\t\t\t\t}\n\t\t\t\telse {}\n\t\t\t}\n\t\t}\n\t\treturn not_found_value\n\t}\n\n\tkey := 'language'\n\tvalue := &Value{\n\t\tval: 'VAL'\n\t}\n\tctx := context.with_value(context.background(), key, value)\n\n\tassert value == f(ctx, key)\n\tassert not_found_value == f(ctx, 'color')\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))\n          (import_name\n            (identifier))\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))))))\n  (struct_declaration\n    (visibility_modifiers)\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (function_type\n          (signature\n            (type_parameter_list\n              (type_parameter_declaration\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))\n              (type_parameter_declaration\n                (plain_type\n                  (qualified_type\n                    (reference_expression\n                      (identifier))\n                    (type_reference_expression\n                      (identifier)))))\n              (type_parameter_declaration\n                (mutability_modifiers)\n                (plain_type\n                  (qualified_type\n                    (reference_expression\n                      (identifier))\n                    (type_reference_expression\n                      (identifier))))))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (function_type\n          (signature\n            (type_parameter_list\n              (type_parameter_declaration\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))\n              (type_parameter_declaration\n                (plain_type\n                  (qualified_type\n                    (reference_expression\n                      (identifier))\n                    (type_reference_expression\n                      (identifier)))))\n              (type_parameter_declaration\n                (mutability_modifiers)\n                (plain_type\n                  (qualified_type\n                    (reference_expression\n                      (identifier))\n                    (type_reference_expression\n                      (identifier)))))\n              (type_parameter_declaration\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (reference_expression\n        (identifier)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (unsafe_expression\n        (block\n          (simple_statement\n            (literal\n              (nil))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (int_literal)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (int_literal))))\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (call_expression\n              (function_literal\n                (signature\n                  (parameter_list\n                    (parameter_declaration\n                      (identifier)\n                      (plain_type\n                        (type_reference_expression\n                          (identifier)))))\n                  (plain_type\n                    (type_reference_expression\n                      (identifier))))\n                (block\n                  (return_statement\n                    (expression_list\n                      (literal\n                        (int_literal))))))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal))))))))\n      (simple_statement\n        (if_expression\n          (is_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (block\n            (simple_statement\n              (go_expression\n                (call_expression\n                  (function_literal\n                    (signature\n                      (parameter_list\n                        (parameter_declaration\n                          (mutability_modifiers)\n                          (identifier)\n                          (plain_type\n                            (type_reference_expression\n                              (identifier))))\n                        (parameter_declaration\n                          (identifier)\n                          (plain_type\n                            (qualified_type\n                              (reference_expression\n                                (identifier))\n                              (type_reference_expression\n                                (identifier)))))))\n                    (block\n                      (simple_statement\n                        (call_expression\n                          (selector_expression\n                            (reference_expression\n                              (identifier))\n                            (reference_expression\n                              (identifier)))\n                          (argument_list\n                            (argument\n                              (literal\n                                (true)))\n                            (argument\n                              (reference_expression\n                                (identifier))))))))\n                  (argument_list\n                    (argument\n                      (mutable_expression\n                        (mutability_modifiers)\n                        (reference_expression\n                          (identifier))))\n                    (argument\n                      (reference_expression\n                        (identifier))))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (function_literal\n              (capture_list\n                (capture\n                  (mutability_modifiers)\n                  (reference_expression\n                    (identifier))))\n              (signature\n                (parameter_list))\n              (block\n                (simple_statement\n                  (call_expression\n                    (selector_expression\n                      (reference_expression\n                        (identifier))\n                      (reference_expression\n                        (identifier)))\n                    (argument_list\n                      (argument\n                        (literal\n                          (true)))\n                      (argument\n                        (reference_expression\n                          (identifier)))))))))))))\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (function_literal\n              (signature\n                (parameter_list\n                  (parameter_declaration\n                    (identifier)\n                    (plain_type\n                      (qualified_type\n                        (reference_expression\n                          (identifier))\n                        (type_reference_expression\n                          (identifier)))))\n                  (parameter_declaration\n                    (identifier)\n                    (plain_type\n                      (qualified_type\n                        (reference_expression\n                          (identifier))\n                        (type_reference_expression\n                          (identifier))))))\n                (plain_type\n                  (pointer_type\n                    (plain_type\n                      (type_reference_expression\n                        (identifier))))))\n              (block\n                (simple_statement\n                  (if_expression\n                    (var_declaration\n                      (expression_list\n                        (reference_expression\n                          (identifier)))\n                      (expression_list\n                        (call_expression\n                          (selector_expression\n                            (reference_expression\n                              (identifier))\n                            (reference_expression\n                              (identifier)))\n                          (argument_list\n                            (argument\n                              (reference_expression\n                                (identifier)))))))\n                    (block\n                      (simple_statement\n                        (match_expression\n                          (reference_expression\n                            (identifier))\n                          (match_arms\n                            (match_arm\n                              (match_expression_list\n                                (reference_expression\n                                  (identifier)))\n                              (block\n                                (return_statement\n                                  (expression_list\n                                    (reference_expression\n                                      (identifier))))))\n                            (match_else_arm_clause\n                              (block))))))))\n                (return_statement\n                  (expression_list\n                    (reference_expression\n                      (identifier)))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (literal\n              (interpreted_string_literal)))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (type_initializer\n              (plain_type\n                (pointer_type\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))\n              (type_initializer_body\n                (element_list\n                  (keyed_element\n                    (field_name\n                      (reference_expression\n                        (identifier)))\n                    (literal\n                      (interpreted_string_literal)))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (call_expression\n                    (selector_expression\n                      (reference_expression\n                        (identifier))\n                      (reference_expression\n                        (identifier)))\n                    (argument_list)))\n                (argument\n                  (reference_expression\n                    (identifier)))\n                (argument\n                  (reference_expression\n                    (identifier))))))))\n      (assert_statement\n        (binary_expression\n          (reference_expression\n            (identifier))\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (reference_expression\n                  (identifier)))\n              (argument\n                (reference_expression\n                  (identifier)))))))\n      (assert_statement\n        (binary_expression\n          (reference_expression\n            (identifier))\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (reference_expression\n                  (identifier)))\n              (argument\n                (literal\n                  (interpreted_string_literal))))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/generics.txt",
    "content": "================================================================================\nGeneric type\n================================================================================\nfn foo() Foo[int] {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list)\n      (plain_type\n        (generic_type\n          (type_reference_expression\n            (identifier))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier)))))))\n    (block)))\n\n================================================================================\nGeneric type with two types\n================================================================================\nfn foo() Foo[int, foo.Bar] {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list)\n      (plain_type\n        (generic_type\n          (type_reference_expression\n            (identifier))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier)))\n            (plain_type\n              (qualified_type\n                (reference_expression\n                  (identifier))\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n\n================================================================================\nGeneric qualified type\n================================================================================\nfn foo() bar.Foo[int] {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list)\n      (plain_type\n        (generic_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier)))))))\n    (block)))\n\n================================================================================\nGeneric struct\n================================================================================\nstruct Foo[T] {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))))\n\n================================================================================\nGeneric struct instantiation\n================================================================================\nFoo[int]{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (generic_type\n          (type_reference_expression\n            (identifier))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (type_initializer_body))))\n\n================================================================================\nGeneric qualified struct instantiation\n================================================================================\nbar.Foo[int]{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (generic_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (type_initializer_body))))\n\n================================================================================\nGeneric function call\n================================================================================\nfoo[int]()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (type_parameters\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (argument_list))))\n\n================================================================================\nGeneric function call with nested generics\n================================================================================\nfoo[int, Bar[string]]()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (type_parameters\n        (plain_type\n          (type_reference_expression\n            (identifier)))\n        (plain_type\n          (generic_type\n            (type_reference_expression\n              (identifier))\n            (type_parameters\n              (plain_type\n                (type_reference_expression\n                  (identifier)))))))\n      (argument_list))))\n\n================================================================================\nType alias with generic type\n================================================================================\ntype Foo[T] = Bar[T]\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (plain_type\n      (generic_type\n        (type_reference_expression\n          (identifier))\n        (type_parameters\n          (plain_type\n            (type_reference_expression\n              (identifier))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/global_var_declaration.txt",
    "content": "================================================================================\nSimple global variable\n================================================================================\n__global g_var = 0\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nSimple global variable with type\n================================================================================\n__global g_var int\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple global variable with complex type\n================================================================================\n__global g_var map[string]int\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (plain_type\n        (map_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))\n          (plain_type\n            (type_reference_expression\n              (identifier))))))))\n\n================================================================================\nMultiline global variable\n================================================================================\n__global (\n    g_var = 100\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline global variables\n================================================================================\n__global (\n    g_var = 100\n    g_var2 = 200\n    g_var3 = 300\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline global variables with type and initializer\n================================================================================\n__global (\n    g_var = 100\n    g_var2 int\n    g_var3 string\n    g_var4 = true\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (global_var_definition\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (global_var_definition\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (global_var_definition\n      (identifier)\n      (literal\n        (true)))))\n\n================================================================================\nEmpty multiline global variables\n================================================================================\n__global ()\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration))\n\n================================================================================\nSimple global variable with attribute\n================================================================================\n[attr]\n__global g_var = 0\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n\n================================================================================\nMultiline global variables with attributes\n================================================================================\n[attr]\n[attr2]\n__global (\n    g_var = 100\n    g_var2 = 200\n    g_var3 = 300\n)\n--------------------------------------------------------------------------------\n\n(source_file\n  (global_var_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))\n    (global_var_definition\n      (identifier)\n      (literal\n        (int_literal)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/hash_statement.txt",
    "content": "================================================================================\nHash statement\n================================================================================\n$if tinyc {\n    #flag -I @VEXEROOT/thirdparty/libgc/include\n    #flag -L @VEXEROOT/thirdparty/tcc/lib\n    #flag -lgc\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (compile_time_if_expression\n      (reference_expression\n        (identifier))\n      (block\n        (hash_statement)\n        (hash_statement)\n        (hash_statement)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/if_expression.txt",
    "content": "================================================================================\nSimple if expression\n================================================================================\nif true {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (literal\n        (true))\n      (block))))\n\n================================================================================\nSimple if expression with braces\n================================================================================\nif (true) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (parenthesized_expression\n        (literal\n          (true)))\n      (block))))\n\n================================================================================\nSimple if expression with else\n================================================================================\nif true {} else {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (literal\n        (true))\n      (block)\n      (else_branch\n        (block)))))\n\n================================================================================\nSimple if expression with else if\n================================================================================\nif true {} else if false {} else {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (literal\n        (true))\n      (block)\n      (else_branch\n        (if_expression\n          (literal\n            (false))\n          (block)\n          (else_branch\n            (block)))))))\n\n================================================================================\nIf guard\n================================================================================\nif a := foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (var_declaration\n        (expression_list\n          (reference_expression\n            (identifier)))\n        (expression_list\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list))))\n      (block))))\n\n================================================================================\nCompile-time if expression\n================================================================================\n$if macos {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (compile_time_if_expression\n      (reference_expression\n        (identifier))\n      (block))))\n\n================================================================================\nCompile-time if expression with else\n================================================================================\n$if macos {} $else {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (compile_time_if_expression\n      (reference_expression\n        (identifier))\n      (block)\n      (block))))\n\n================================================================================\nCompile-time if expression with else if\n================================================================================\n$if macos {\n    println(1)\n} $else $if linux {\n    println(1)\n} $else {\n    println(1)\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (compile_time_if_expression\n      (reference_expression\n        (identifier))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (literal\n                  (int_literal)))))))\n      (compile_time_if_expression\n        (reference_expression\n          (identifier))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal)))))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal)))))))))))\n\n================================================================================\nCompile-time if expression with ?\n================================================================================\n$if some_define ? {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (compile_time_if_expression\n      (option_propagation_expression\n        (reference_expression\n          (identifier)))\n      (block))))\n\n================================================================================\nSimple block\n================================================================================\nif true { f();g();h(); }\nif true { f()\ng()\n  h(); }\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (literal\n        (true))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list))))))\n  (simple_statement\n    (if_expression\n      (literal\n        (true))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/imports.txt",
    "content": "================================================================================\nSimple import\n================================================================================\nimport foo\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))))\n\n================================================================================\nSimple import list\n================================================================================\nimport foo\nimport bar\nimport baz\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))))\n\n================================================================================\nImport with alias\n================================================================================\nimport foo as bar\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))))\n\n================================================================================\nImport list with alias\n================================================================================\nimport foo as bar\nimport baz as qux\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))))\n\n================================================================================\nImport list with alias and no alias\n================================================================================\nimport foo as bar\nimport baz\nimport qux as quux\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))))\n\n================================================================================\nImport with fqn\n================================================================================\nimport foo.bar.baz\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))\n          (import_name\n            (identifier))\n          (import_name\n            (identifier)))))))\n\n================================================================================\nImport with fqn and alias\n================================================================================\nimport foo.bar.baz as qux\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))\n          (import_name\n            (identifier))\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))))\n\n================================================================================\nSimple selective import\n================================================================================\nimport foo { bar }\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSelective import with several items\n================================================================================\nimport foo { Bar, baz, qux }\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSelective import with several items and trailing comma\n================================================================================\nimport foo { bar, baz, qux, }\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSelective import with multiline comma separated several items\n================================================================================\nimport foo {\n    bar,\n    baz,\n    qux,\n}\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSelective import with multiline new line separated several items\n================================================================================\nimport foo {\n    bar\n    baz\n    Qux\n}\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSelective import with several items and alias\n================================================================================\nimport foo as bar { bar, Baz, qux, }\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/in_expression.txt",
    "content": "================================================================================\nSimple in expression\n================================================================================\n10 in [1, 2, 3]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (in_expression\n      (literal\n        (int_literal))\n      (array_creation\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))))\n\n================================================================================\nSimple not in expression\n================================================================================\n10 !in [1, 2, 3]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (in_expression\n      (literal\n        (int_literal))\n      (array_creation\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/interface_declaration.txt",
    "content": "================================================================================\nSimple interface\n================================================================================\ninterface Foo {\n    name string\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple public interface\n================================================================================\npub interface Foo {\n    name string\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (visibility_modifiers)\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple interface with several methods\n================================================================================\ninterface Foo {\n    do() string\n    foo(name string) ?string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (type_reference_expression\n                (identifier)))))\n        (plain_type\n          (option_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))))))))\n\n================================================================================\nSimple interface with scopes\n================================================================================\ninterface Foo {\nmut:\n    name string\nmut:\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nInterface with field with default type and attribute\n================================================================================\ninterface Foo {\n    name string = '' [json: 'Name']\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (interpreted_string_literal))\n      (attribute\n        (attribute_expression\n          (key_value_attribute\n            (value_attribute\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal))))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple interface with attributes\n================================================================================\n[attr]\n[attr2]\ninterface Foo {\n    name string\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple interface with attributes and comment\n================================================================================\n// Foo is a simple interface\n[attr]\n[attr2]\ninterface Foo {\n    name string\n    do() string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (interface_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier)))))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nInterface embedding\n================================================================================\ninterface Foo {\n    Embedded\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nInterface with several embedded interfaces\n================================================================================\ninterface Foo {\n    Embedded\n    Embedded2\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nGeneric interface\n================================================================================\ninterface Foo[T] {\n    name T\n    do() T\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (interface_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (interface_method_definition\n      (identifier)\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/is_as_expression.txt",
    "content": "================================================================================\nSimple is expression\n================================================================================\nif a is []Any {\n} else if a is map[string]Any {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (array_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)\n      (else_branch\n        (if_expression\n          (is_expression\n            (reference_expression\n              (identifier))\n            (plain_type\n              (map_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))\n          (block))))))\n\n================================================================================\nIs expression with qualified type\n================================================================================\nif a is foo.Bar {\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))))\n      (block))))\n\n================================================================================\nIs expression with mut\n================================================================================\nif mut run is Block {\n    println()\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (is_expression\n        (mutability_modifiers)\n        (reference_expression\n          (identifier))\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))))))\n\n================================================================================\nNot is expression with mut\n================================================================================\nif mut run !is Block {\n    println()\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (is_expression\n        (mutability_modifiers)\n        (reference_expression\n          (identifier))\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))))))\n\n================================================================================\nIs expression with selector expression\n================================================================================\nif element is psi.StructDeclaration {\n    return\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (is_expression\n        (reference_expression\n          (identifier))\n        (plain_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))))\n      (block\n        (return_statement)))))\n\n================================================================================\nIs and as expressions\n================================================================================\n\n// array returns `Any` as an array.\npub fn (a Any) array() []Any {\n\tif a is []Any {\n\t\treturn a\n\t} else if a is map[string]Any {\n\t\tmut arr := []Any{}\n\t\tfor _, v in a {\n\t\t\tarr << v\n\t\t}\n\t\treturn arr\n\t}\n\treturn [a]\n}\n\nfn test_parse_compact_text() {\n\ttoml_doc := toml.parse_text(toml_text) or { panic(err) }\n\n\ttitle := toml_doc.value('title')\n\tassert title == toml.Any('TOML Example')\n\tassert title as string == 'TOML Example'\n\n\tdatabase := toml_doc.value('database') as map[string]toml.Any\n\tdb_serv := database[1] or {\n\t\tpanic('could not access \"server\" index in \"database\" variable')\n\t}\n\tassert db_serv as string == '192.168.1.1'\n\n\tassert toml_doc.value('owner.name') as string == 'Tom Preston-Werner'\n\n\tassert toml_doc.value('database.server') as string == '192.168.1.1'\n\n\tdatabase_ports := toml_doc.value('database.ports') as []toml.Any\n\tassert database_ports[0] as i64 == 8000\n\tassert database_ports[1] as i64 == 8001\n\tassert database_ports[2] as i64 == 8002\n\tassert database_ports[0].int() == 8000\n\tassert database_ports[1].int() == 8001\n\tassert database_ports[2].int() == 8002\n\n\tassert toml_doc.value('database.connection_max') as i64 == 5000\n\tassert toml_doc.value('database.enabled') as bool == true\n\n\tassert toml_doc.value('servers.alpha.ip').string() == '10.0.0.1'\n\tassert toml_doc.value('servers.alpha.dc').string() == 'eqdc10'\n\n\tassert toml_doc.value('servers.beta.ip').string() == '10.0.0.2'\n\tassert toml_doc.value('servers.beta.dc').string() == 'eqdc10'\n\n\tclients_data := (toml_doc.value('clients.data') as []toml.Any)\n\t// dump(clients_data)\n\t// assert false\n\tgamma_delta_array := clients_data[0] as []toml.Any\n\tdigits_array := clients_data[1] as []toml.Any\n\tassert gamma_delta_array[0].string() == 'gamma'\n\tassert gamma_delta_array[1].string() == 'delta'\n\tassert digits_array[0].int() == 1\n\tassert digits_array[1].int() == 2\n\n\tclients_hosts := (toml_doc.value('clients.hosts') as []toml.Any).as_strings()\n\tassert clients_hosts[0] == 'alpha'\n\tassert clients_hosts[1] == 'omega'\n}\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (function_declaration\n    (visibility_modifiers)\n    (receiver\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (identifier)\n    (signature\n      (parameter_list)\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block\n      (simple_statement\n        (if_expression\n          (is_expression\n            (reference_expression\n              (identifier))\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))\n          (block\n            (return_statement\n              (expression_list\n                (reference_expression\n                  (identifier)))))\n          (else_branch\n            (if_expression\n              (is_expression\n                (reference_expression\n                  (identifier))\n                (plain_type\n                  (map_type\n                    (plain_type\n                      (type_reference_expression\n                        (identifier)))\n                    (plain_type\n                      (type_reference_expression\n                        (identifier))))))\n              (block\n                (simple_statement\n                  (var_declaration\n                    (expression_list\n                      (mutable_expression\n                        (mutability_modifiers)\n                        (reference_expression\n                          (identifier))))\n                    (expression_list\n                      (type_initializer\n                        (plain_type\n                          (array_type\n                            (plain_type\n                              (type_reference_expression\n                                (identifier)))))\n                        (type_initializer_body)))))\n                (for_statement\n                  (range_clause\n                    (var_definition_list\n                      (var_definition\n                        (identifier))\n                      (var_definition\n                        (identifier)))\n                    (reference_expression\n                      (identifier)))\n                  (block\n                    (append_statement\n                      (reference_expression\n                        (identifier))\n                      (reference_expression\n                        (identifier)))))\n                (return_statement\n                  (expression_list\n                    (reference_expression\n                      (identifier)))))))))\n      (return_statement\n        (expression_list\n          (array_creation\n            (reference_expression\n              (identifier)))))))\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (or_block_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (reference_expression\n                      (identifier)))))\n              (or_block\n                (block\n                  (simple_statement\n                    (call_expression\n                      (reference_expression\n                        (identifier))\n                      (argument_list\n                        (argument\n                          (reference_expression\n                            (identifier))))))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (literal\n                    (interpreted_string_literal))))))))\n      (assert_statement\n        (binary_expression\n          (reference_expression\n            (identifier))\n          (call_expression\n            (selector_expression\n              (reference_expression\n                (identifier))\n              (reference_expression\n                (identifier)))\n            (argument_list\n              (argument\n                (literal\n                  (interpreted_string_literal)))))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (reference_expression\n              (identifier))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (interpreted_string_literal))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (as_type_cast_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (plain_type\n                (map_type\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))\n                  (plain_type\n                    (qualified_type\n                      (reference_expression\n                        (identifier))\n                      (type_reference_expression\n                        (identifier))))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (or_block_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (or_block\n                (block\n                  (simple_statement\n                    (call_expression\n                      (reference_expression\n                        (identifier))\n                      (argument_list\n                        (argument\n                          (literal\n                            (interpreted_string_literal))))))))))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (reference_expression\n              (identifier))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (literal\n                    (interpreted_string_literal)))))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (literal\n                    (interpreted_string_literal)))))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (interpreted_string_literal))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (as_type_cast_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (plain_type\n                (array_type\n                  (plain_type\n                    (qualified_type\n                      (reference_expression\n                        (identifier))\n                      (type_reference_expression\n                        (identifier))))))))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (index_expression\n              (reference_expression\n                (identifier))\n              (literal\n                (int_literal)))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (index_expression\n              (reference_expression\n                (identifier))\n              (literal\n                (int_literal)))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (index_expression\n              (reference_expression\n                (identifier))\n              (literal\n                (int_literal)))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (literal\n                    (interpreted_string_literal)))))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (as_type_cast_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list\n                (argument\n                  (literal\n                    (interpreted_string_literal)))))\n            (plain_type\n              (type_reference_expression\n                (identifier))))\n          (literal\n            (true))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (call_expression\n                (selector_expression\n                  (reference_expression\n                    (identifier))\n                  (reference_expression\n                    (identifier)))\n                (argument_list\n                  (argument\n                    (literal\n                      (interpreted_string_literal)))))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (parenthesized_expression\n              (as_type_cast_expression\n                (call_expression\n                  (selector_expression\n                    (reference_expression\n                      (identifier))\n                    (reference_expression\n                      (identifier)))\n                  (argument_list\n                    (argument\n                      (literal\n                        (interpreted_string_literal)))))\n                (plain_type\n                  (array_type\n                    (plain_type\n                      (qualified_type\n                        (reference_expression\n                          (identifier))\n                        (type_reference_expression\n                          (identifier)))))))))))\n      (line_comment)\n      (line_comment)\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (as_type_cast_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (plain_type\n                (array_type\n                  (plain_type\n                    (qualified_type\n                      (reference_expression\n                        (identifier))\n                      (type_reference_expression\n                        (identifier))))))))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (as_type_cast_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (plain_type\n                (array_type\n                  (plain_type\n                    (qualified_type\n                      (reference_expression\n                        (identifier))\n                      (type_reference_expression\n                        (identifier))))))))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (int_literal))))\n      (assert_statement\n        (binary_expression\n          (call_expression\n            (selector_expression\n              (index_expression\n                (reference_expression\n                  (identifier))\n                (literal\n                  (int_literal)))\n              (reference_expression\n                (identifier)))\n            (argument_list))\n          (literal\n            (int_literal))))\n      (simple_statement\n        (var_declaration\n          (expression_list\n            (reference_expression\n              (identifier)))\n          (expression_list\n            (call_expression\n              (selector_expression\n                (parenthesized_expression\n                  (as_type_cast_expression\n                    (call_expression\n                      (selector_expression\n                        (reference_expression\n                          (identifier))\n                        (reference_expression\n                          (identifier)))\n                      (argument_list\n                        (argument\n                          (literal\n                            (interpreted_string_literal)))))\n                    (plain_type\n                      (array_type\n                        (plain_type\n                          (qualified_type\n                            (reference_expression\n                              (identifier))\n                            (type_reference_expression\n                              (identifier))))))))\n                (reference_expression\n                  (identifier)))\n              (argument_list)))))\n      (assert_statement\n        (binary_expression\n          (index_expression\n            (reference_expression\n              (identifier))\n            (literal\n              (int_literal)))\n          (literal\n            (interpreted_string_literal))))\n      (assert_statement\n        (binary_expression\n          (index_expression\n            (reference_expression\n              (identifier))\n            (literal\n              (int_literal)))\n          (literal\n            (interpreted_string_literal)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/json_call.txt",
    "content": "================================================================================\nSimple json.decode call expression\n================================================================================\na := json.decode([]Foo, data)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (call_expression\n          (special_argument_list\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))))\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple json.decode call expression with array\n================================================================================\njson.decode([]Foo, data)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (special_argument_list\n        (plain_type\n          (array_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))))\n        (reference_expression\n          (identifier))))))\n\n================================================================================\nSimple json.decode call expression with map\n================================================================================\njson.decode(map[string]Foo, data)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (special_argument_list\n        (plain_type\n          (map_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))\n            (plain_type\n              (type_reference_expression\n                (identifier)))))\n        (reference_expression\n          (identifier))))))\n\n================================================================================\nSimple json.encode call expression\n================================================================================\njson.encode(data)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (selector_expression\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (argument_list\n        (argument\n          (reference_expression\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/labeled_statement.txt",
    "content": "================================================================================\nSimple labeled for\n================================================================================\nlabel: for i in 0 .. 10 {\n    println(i)\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (labeled_statement\n    (label_definition\n      (identifier))\n    (for_statement\n      (range_clause\n        (var_definition_list\n          (var_definition\n            (identifier)))\n        (range\n          (literal\n            (int_literal))\n          (literal\n            (int_literal))))\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list\n              (argument\n                (reference_expression\n                  (identifier))))))))))\n\n================================================================================\nBreak/continue/goto with label\n================================================================================\nlabel: for i in 0 .. 10 {\n    break label\n    continue label\n    goto label\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (labeled_statement\n    (label_definition\n      (identifier))\n    (for_statement\n      (range_clause\n        (var_definition_list\n          (var_definition\n            (identifier)))\n        (range\n          (literal\n            (int_literal))\n          (literal\n            (int_literal))))\n      (block\n        (break_statement\n          (label_reference\n            (identifier)))\n        (continue_statement\n          (label_reference\n            (identifier)))\n        (goto_statement\n          (label_reference\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/lock_expression.txt",
    "content": "================================================================================\nSimple lock expression\n================================================================================\nlock a {\n    return\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (lock_expression\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (block\n        (return_statement)))))\n\n================================================================================\nSimple rlock expression\n================================================================================\nrlock a {\n    return\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (lock_expression\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (block\n        (return_statement)))))\n\n================================================================================\nSimple lock expression with several expressions\n================================================================================\nrlock a, b.name, c.other.foo {\n    return\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (lock_expression\n      (expression_list\n        (reference_expression\n          (identifier))\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))\n        (selector_expression\n          (selector_expression\n            (reference_expression\n              (identifier))\n            (reference_expression\n              (identifier)))\n          (reference_expression\n            (identifier))))\n      (block\n        (return_statement)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/map_init_expression.txt",
    "content": "================================================================================\nSimple map init expression\n================================================================================\n{\n    '0': 1\n    1: 2\n    true: 3\n    Foo.name: 4\n    .name: 5\n    1 + 3: 6\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (map_init_expression\n      (map_keyed_element\n        (literal\n          (interpreted_string_literal))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (literal\n          (int_literal))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (literal\n          (true))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (selector_expression\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (enum_fetch\n          (reference_expression\n            (identifier)))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (binary_expression\n          (literal\n            (int_literal))\n          (literal\n            (int_literal)))\n        (literal\n          (int_literal))))))\n\n================================================================================\nEmpty map initialization\n================================================================================\nfoo({})\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (map_init_expression))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/match_expression.txt",
    "content": "================================================================================\nSimple match expression\n================================================================================\nmatch age {\n    100 {}\n    200 {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))))))\n\n================================================================================\nSimple match expression with else\n================================================================================\nmatch age {\n    100 {}\n    else {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))\n        (match_else_arm_clause\n          (block))))))\n\n================================================================================\nSimple match expression with several else\n================================================================================\nmatch age {\n    100 {}\n    200 {}\n    else {}\n    else {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))\n        (match_else_arm_clause\n          (block))\n        (match_else_arm_clause\n          (block))))))\n\n================================================================================\nSimple match expression with mutable expression\n================================================================================\nmatch mut age {\n    100 {}\n    200 {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (mutable_expression\n        (mutability_modifiers)\n        (reference_expression\n          (identifier)))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal)))\n          (block))))))\n\n================================================================================\nSimple match expression with several expression in case\n================================================================================\nmatch mut age {\n    100, 200 {}\n    200, 300 {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (mutable_expression\n        (mutability_modifiers)\n        (reference_expression\n          (identifier)))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal))\n            (literal\n              (int_literal)))\n          (block))\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal))\n            (literal\n              (int_literal)))\n          (block))))))\n\n================================================================================\nSimple match expression with range\n================================================================================\nmatch b {\n  33, 35...39, 42 { true }\n  else { false }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (literal\n              (int_literal))\n            (range\n              (literal\n                (int_literal))\n              (literal\n                (int_literal)))\n            (literal\n              (int_literal)))\n          (block\n            (simple_statement\n              (literal\n                (true)))))\n        (match_else_arm_clause\n          (block\n            (simple_statement\n              (literal\n                (false)))))))))\n\n================================================================================\nSimple match expression for types\n================================================================================\nmatch age {\n    []string {}\n    int {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (in_expression\n              (type_initializer\n                (plain_type\n                  (array_type\n                    (plain_type\n                      (type_reference_expression\n                        (identifier)))))\n                (type_initializer_body))\n              (reference_expression\n                (identifier))))\n          (block))))))\n\n================================================================================\nSimple match expression for other types\n================================================================================\nmatch age {\n    map[int]string {}\n    &int {}\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (match_expression\n      (reference_expression\n        (identifier))\n      (match_arms\n        (match_arm\n          (match_expression_list\n            (binary_expression\n              (type_initializer\n                (plain_type\n                  (map_type\n                    (plain_type\n                      (type_reference_expression\n                        (identifier)))\n                    (plain_type\n                      (type_reference_expression\n                        (identifier)))))\n                (type_initializer_body))\n              (reference_expression\n                (identifier))))\n          (block))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/method_declaration.txt",
    "content": "================================================================================\nSimple method\n================================================================================\nfn (f Foo) foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple method with mutable receiver\n================================================================================\nfn (mut f Foo) foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (mutability_modifiers)\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple method with shared receiver\n================================================================================\nfn (shared f Foo) foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (mutability_modifiers)\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSimple method with pointer receiver\n================================================================================\nfn (f &Foo) foo() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (identifier)\n      (plain_type\n        (pointer_type\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nOverload method\n================================================================================\nfn (f Foo) == (o Foo) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (overridable_operator)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier))))))\n    (block)))\n\n================================================================================\nMethod with mutable receiver and parameters\n================================================================================\nfn (mut r ResolveProcessor) execute(element PsiElement) bool {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (receiver\n      (mutability_modifiers)\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (block)))\n\n================================================================================\nMethod with array parameter\n================================================================================\npub fn new_stubs_index(sinks []StubIndexSink) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (visibility_modifiers)\n    (identifier)\n    (signature\n      (parameter_list\n        (parameter_declaration\n          (identifier)\n          (plain_type\n            (array_type\n              (plain_type\n                (type_reference_expression\n                  (identifier))))))))\n    (block)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/module_clause.txt",
    "content": "================================================================================\nSimple module clause\n================================================================================\nmodule main\n--------------------------------------------------------------------------------\n\n(source_file\n  (module_clause\n    (identifier)))\n\n================================================================================\nSimple module clause with comment\n================================================================================\n// This is a comment\n// with two lines\nmodule main\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (line_comment)\n  (module_clause\n    (identifier)))\n\n================================================================================\nModule clause with attributes\n================================================================================\n[module_attribute]\nmodule main\n--------------------------------------------------------------------------------\n\n(source_file\n  (module_clause\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)))\n\n================================================================================\nModule clause with attributes and comments\n================================================================================\n// This is a comment\n// with two lines\n[module_attribute]\nmodule main\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (line_comment)\n  (module_clause\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/safe_access.txt",
    "content": "================================================================================\nSimple safe access\n================================================================================\nfoo?.name\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (selector_expression\n      (reference_expression\n        (identifier))\n      (reference_expression\n        (identifier)))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/select_expression.txt",
    "content": "================================================================================\nSimple select expression\n================================================================================\nselect {\n    c <- x {\n        println(100)\n    }\n    _ := <-quit {\n        println(100)\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (select_expression\n      (select_arm\n        (select_arm_statement\n          (send_statement\n            (reference_expression\n              (identifier))\n            (reference_expression\n              (identifier))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal))))))))\n      (select_arm\n        (select_arm_statement\n          (var_declaration\n            (identifier_list\n              (identifier))\n            (expression_list\n              (receive_expression\n                (reference_expression\n                  (identifier))))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal)))))))))))\n\n================================================================================\nSimple select expression with timeout branch\n================================================================================\nselect {\n    2 * time.second {\n        println(100)\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (select_expression\n      (select_arm\n        (select_arm_statement\n          (expression_list\n            (binary_expression\n              (literal\n                (int_literal))\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier))))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal)))))))))))\n\n================================================================================\nSimple select expression with else branch\n================================================================================\nselect {\n    c <- x {\n        println(100)\n    }\n    _ := <-quit {\n        println(200)\n    }\n    else {\n        println(300)\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (select_expression\n      (select_arm\n        (select_arm_statement\n          (send_statement\n            (reference_expression\n              (identifier))\n            (reference_expression\n              (identifier))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal))))))))\n      (select_arm\n        (select_arm_statement\n          (var_declaration\n            (identifier_list\n              (identifier))\n            (expression_list\n              (receive_expression\n                (reference_expression\n                  (identifier))))))\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal))))))))\n      (select_else_arn_clause\n        (block\n          (simple_statement\n            (call_expression\n              (reference_expression\n                (identifier))\n              (argument_list\n                (argument\n                  (literal\n                    (int_literal)))))))))))\n\n================================================================================\nSimple select expression as an expression\n================================================================================\nif select {\n    ch <- a {\n        // ...\n    }\n} {\n    // channel was open\n} else {\n    // channel is closed\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (if_expression\n      (select_expression\n        (select_arm\n          (select_arm_statement\n            (send_statement\n              (reference_expression\n                (identifier))\n              (reference_expression\n                (identifier))))\n          (block\n            (line_comment))))\n      (block\n        (line_comment))\n      (else_branch\n        (block\n          (line_comment))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/shebang.txt",
    "content": "================================================================================\nShebang\n================================================================================\n#!/usr/bin/env -S v\n\nfoo := 'foo'\n--------------------------------------------------------------------------------\n\n(source_file\n  (shebang)\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (literal\n          (interpreted_string_literal))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/slice_expression.txt",
    "content": "================================================================================\nSimple slice expression\n================================================================================\nname[0..10]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))))\n\n================================================================================\nSlice expression with only left index\n================================================================================\nname[0..]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range\n        (literal\n          (int_literal))))))\n\n================================================================================\nSlice expression with only right index\n================================================================================\nname[..10]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range\n        (literal\n          (int_literal))))))\n\n================================================================================\nSlice expression without indices\n================================================================================\nname[..]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range))))\n\n================================================================================\nSlice expression with binary expression indices\n================================================================================\nname[10 + 4..20 + 10]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range\n        (binary_expression\n          (literal\n            (int_literal))\n          (literal\n            (int_literal)))\n        (binary_expression\n          (literal\n            (int_literal))\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSafe slice expression\n================================================================================\nname#[0..10]\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (slice_expression\n      (reference_expression\n        (identifier))\n      (range\n        (literal\n          (int_literal))\n        (literal\n          (int_literal))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/source_file.txt",
    "content": "================================================================================\nSimple source file\n================================================================================\nfn main() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSource file with module\n================================================================================\nmodule main\n\nfn main() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (module_clause\n    (identifier))\n  (function_declaration\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nSource file with top level statements\n================================================================================\nmodule main\n\nprintln(100)\n--------------------------------------------------------------------------------\n\n(source_file\n  (module_clause\n    (identifier))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (int_literal)))))))\n\n================================================================================\nSource file with module clause and imports\n================================================================================\nmodule main\n\nimport bar\nimport foo as f\nimport foo.bar as fb\nimport foo.bar.baz as fbb { Foo, Bar }\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (module_clause\n    (identifier))\n  (import_list\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))))\n    (import_declaration\n      (import_spec\n        (import_path\n          (import_name\n            (identifier))\n          (import_name\n            (identifier))\n          (import_name\n            (identifier)))\n        (import_alias\n          (import_name\n            (identifier)))\n        (selective_import_list\n          (reference_expression\n            (identifier))\n          (reference_expression\n            (identifier)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/spawn_expression.txt",
    "content": "================================================================================\nSimple spawn expression\n================================================================================\nspawn foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (spawn_expression\n      (call_expression\n        (reference_expression\n          (identifier))\n        (argument_list)))))\n\n================================================================================\nSimple spawn expression with function literal\n================================================================================\nspawn fn () {\n    return\n}()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (spawn_expression\n      (call_expression\n        (function_literal\n          (signature\n            (parameter_list))\n          (block\n            (return_statement)))\n        (argument_list)))))\n\n================================================================================\nSimple spawn expression with assignment\n================================================================================\na := spawn foo()\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (spawn_expression\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/special_call_expression.txt",
    "content": "================================================================================\njson.decode call\n================================================================================\njson.decode([]User, data)\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (call_expression\n      (special_argument_list\n        (plain_type\n          (array_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))))\n        (reference_expression\n          (identifier))))))\n\n================================================================================\njson.decode call with propagate\n================================================================================\njson.decode([]User, data)!\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (result_propagation_expression\n      (call_expression\n        (special_argument_list\n          (plain_type\n            (array_type\n              (plain_type\n                (type_reference_expression\n                  (identifier)))))\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\njson.decode call with or block\n================================================================================\njson.decode([]User, data) or {\n    return\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (or_block_expression\n      (call_expression\n        (special_argument_list\n          (plain_type\n            (array_type\n              (plain_type\n                (type_reference_expression\n                  (identifier)))))\n          (reference_expression\n            (identifier))))\n      (or_block\n        (block\n          (return_statement))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/static_method_declaration.txt",
    "content": "================================================================================\nSimple static method\n================================================================================\nfn Foo.method() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (static_method_declaration\n    (static_receiver\n      (reference_expression\n        (identifier)))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nStatic method with attributes\n================================================================================\n[unsafe]\nfn Foo.method() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (static_method_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression)))))\n    (static_receiver\n      (reference_expression\n        (identifier)))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nPublic static method\n================================================================================\npub fn Foo.method() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (static_method_declaration\n    (visibility_modifiers)\n    (static_receiver\n      (reference_expression\n        (identifier)))\n    (identifier)\n    (signature\n      (parameter_list))\n    (block)))\n\n================================================================================\nStatic method with generics\n================================================================================\nfn Foo.method[T]() {}\nfn Foo.method[T, R]() {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (static_method_declaration\n    (static_receiver\n      (reference_expression\n        (identifier)))\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list))\n    (block))\n  (static_method_declaration\n    (static_receiver\n      (reference_expression\n        (identifier)))\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (signature\n      (parameter_list))\n    (block)))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/string_literal.txt",
    "content": "================================================================================\nEmpty string\n================================================================================\n''\nc''\nr''\n\"\"\nc\"\"\nr\"\"\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (c_string_literal)))\n  (simple_statement\n    (literal\n      (raw_string_literal)))\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (c_string_literal)))\n  (simple_statement\n    (literal\n      (raw_string_literal))))\n\n================================================================================\nComments string\n================================================================================\n'//'\n'/**/'\nc'//'\nc'/**/'\nr'//'\nr'/**/'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (c_string_literal)))\n  (simple_statement\n    (literal\n      (c_string_literal)))\n  (simple_statement\n    (literal\n      (raw_string_literal)))\n  (simple_statement\n    (literal\n      (raw_string_literal))))\n\n================================================================================\nSimple string interpolation\n================================================================================\n'Hello, ${name}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))))))\n\n================================================================================\nSeveral string interpolations\n================================================================================\n'Hello, ${name} and ${other}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))))))\n\n================================================================================\nSimple escaped string interpolation\n================================================================================\n'Hello, \\${name}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (escape_sequence)))))\n\n================================================================================\nString interpolation at start\n================================================================================\n'${name}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))))))\n\n================================================================================\nString interpolation at end\n================================================================================\n'${name}'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (reference_expression\n              (identifier)))\n          (interpolation_closing))))))\n\n================================================================================\nString interpolation with complex expression\n================================================================================\n'Hello, ${name.foo()}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (call_expression\n              (selector_expression\n                (reference_expression\n                  (identifier))\n                (reference_expression\n                  (identifier)))\n              (argument_list)))\n          (interpolation_closing))))))\n\n================================================================================\nString interpolation with complex expressions and format specifiers\n================================================================================\nx := 123.4567\nprintln('[${x:.2}]')\nprintln('[${x:10}]')\nprintln('[${int(x):-10}]')\nprintln('[${int(x):010}]')\nprintln('[${int(x):b}]')\nprintln('[${int(x):o}]')\nprintln('[${int(x):X}]')\nprintln('[${10.0000:.2}]')\nprintln('[${10.0000:+.2f}]')\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (literal\n          (float_literal)))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (reference_expression\n                    (identifier)))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (reference_expression\n                    (identifier)))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (call_expression\n                    (reference_expression\n                      (identifier))\n                    (argument_list\n                      (argument\n                        (reference_expression\n                          (identifier))))))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (call_expression\n                    (reference_expression\n                      (identifier))\n                    (argument_list\n                      (argument\n                        (reference_expression\n                          (identifier))))))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (call_expression\n                    (reference_expression\n                      (identifier))\n                    (argument_list\n                      (argument\n                        (reference_expression\n                          (identifier))))))\n                (format_specifier)\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (call_expression\n                    (reference_expression\n                      (identifier))\n                    (argument_list\n                      (argument\n                        (reference_expression\n                          (identifier))))))\n                (format_specifier)\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (call_expression\n                    (reference_expression\n                      (identifier))\n                    (argument_list\n                      (argument\n                        (reference_expression\n                          (identifier))))))\n                (format_specifier)\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (literal\n                    (float_literal)))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing))))))))\n  (simple_statement\n    (call_expression\n      (reference_expression\n        (identifier))\n      (argument_list\n        (argument\n          (literal\n            (interpreted_string_literal\n              (string_interpolation\n                (interpolation_opening)\n                (interpolation_expression\n                  (literal\n                    (float_literal)))\n                (format_specifier\n                  (int_literal))\n                (interpolation_closing)))))))))\n\n================================================================================\nC string literal\n================================================================================\nc'Hello, World!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (c_string_literal))))\n\n================================================================================\nRaw string literal\n================================================================================\nr'Hello, World!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (raw_string_literal))))\n\n================================================================================\nRaw string literal with interpolation\n================================================================================\nr'Hello, ${name}!'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (raw_string_literal))))\n\n================================================================================\nString literal with escape sequences\n================================================================================\n'Hello, \\''\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (escape_sequence)))))\n\n================================================================================\nString literal with identifier tokens\n================================================================================\n'$Hello'\n'C.Hello $World'\n'@Hello\n$\nJS.World'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (interpreted_string_literal)))\n  (simple_statement\n    (literal\n      (interpreted_string_literal))))\n\n================================================================================\nString literal with interpolation after \\n\n================================================================================\n'v fmt failed:\\n\\n${res.output}'\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (interpreted_string_literal\n        (escape_sequence)\n        (escape_sequence)\n        (string_interpolation\n          (interpolation_opening)\n          (interpolation_expression\n            (selector_expression\n              (reference_expression\n                (identifier))\n              (reference_expression\n                (identifier))))\n          (interpolation_closing))))))\n\n================================================================================\nRaw String literal with \\\n================================================================================\nr'\\'\nr\"\\\"\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (literal\n      (raw_string_literal)))\n  (simple_statement\n    (literal\n      (raw_string_literal))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/struct_declaration.txt",
    "content": "================================================================================\nSimple struct\n================================================================================\nstruct Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple public struct\n================================================================================\npub struct Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (visibility_modifiers)\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple union\n================================================================================\nunion Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple empty struct\n================================================================================\nstruct Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)))\n\n================================================================================\nSimple struct with attribute\n================================================================================\n[heap]\nstruct Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with attribute and comment\n================================================================================\n// This is a comment\n[heap]\nstruct Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (line_comment)\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with several fields\n================================================================================\nstruct Foo {\n    name  string\n    age   int\n    other f32\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with several fields with different scopes\n================================================================================\nstruct Foo {\n    name  string\nmut:\n    age   int\npub:\n    other f32\npub mut:\n    other2 bool\n__global:\n    other3 i8\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with modifier with space before colon\n================================================================================\nstruct Foo {\nmut :\n    age   int\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with not ended modifier\n================================================================================\nstruct Foo {\nmut\n    age   int\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (ERROR)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with several fields and embedding\n================================================================================\nstruct Foo {\n    Embedded\n    name  string\n    age   int\n    other f32\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with several embedding\n================================================================================\nstruct Foo {\n    Embedded\n    Embedded2\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with qualified embedding\n================================================================================\nstruct Foo {\n    foo.Embedded\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (qualified_type\n          (reference_expression\n            (identifier))\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple struct with several embedding and fields\n================================================================================\nstruct Foo {\n    Embedded\n    Embedded2\n    name  string\nmut:\n    age   int\npub:\n    other f32\npub mut:\n    other2 bool\n__global:\n    other3 i8\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (embedded_definition\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSimple struct with fields with default values\n================================================================================\nstruct Foo {\n    name  bool = true\n    age   int = 10\n    other f32 = 3.14\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (true)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (int_literal)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (float_literal)))))\n\n================================================================================\nSimple struct with fields with attributes\n================================================================================\nstruct Foo {\n    name  string [attr]\n    age   int    [attr]\n    other f32    [attr; omitempty]\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple struct with fields with attributes and default values\n================================================================================\nstruct Foo {\n    name  string [attr]\n    age   int    = 10 [attr]\n    other f32    = 3.14 [attr; omitempty]\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (int_literal))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (float_literal))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple generic struct\n================================================================================\nstruct Foo[T] {\n    value T\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nGeneric struct with several generic parameters\n================================================================================\nstruct Foo[T, U, V] {\n    value T\n    value2 U\n    value3 V\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nC struct\n================================================================================\n[typedef]\nstruct C.Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nJS struct\n================================================================================\n[heap]\nstruct JS.Foo {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (attributes\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nStruct all in one\n================================================================================\nstruct Hello {\n    hidden string\npub:\n    foo string [attr]\n    bar int = 10\npub mut:\n    baz int\n__global:\n    blu i64\n}\n\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (identifier)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (attribute\n        (attribute_expression\n          (value_attribute\n            (reference_expression\n              (identifier))))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (literal\n        (int_literal)))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))\n    (struct_field_scope)\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nStruct with single explicit interface implementation\n================================================================================\npub struct Foo implements Bar {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (visibility_modifiers)\n    (identifier)\n    (implements_clause\n      (type_reference_expression\n        (identifier)))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nStruct with multiple explicit interface implementations\n================================================================================\npub struct Foo implements Interface1, Interface2, qualified.Interface3 {\n    name string\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (struct_declaration\n    (visibility_modifiers)\n    (identifier)\n    (implements_clause\n      (type_reference_expression\n        (identifier))\n      (type_reference_expression\n        (identifier))\n      (qualified_type\n        (reference_expression\n          (identifier))\n        (type_reference_expression\n          (identifier))))\n    (struct_field_declaration\n      (identifier)\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/type_declaration.txt",
    "content": "================================================================================\nSimple type declaration\n================================================================================\ntype String = string\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (plain_type\n      (type_reference_expression\n        (identifier)))))\n\n================================================================================\nSimple type declaration with visibility modifier\n================================================================================\npub type String = string\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (visibility_modifiers)\n    (identifier)\n    (plain_type\n      (type_reference_expression\n        (identifier)))))\n\n================================================================================\nGeneric type declaration\n================================================================================\ntype Container[T] = []T\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier)))\n    (plain_type\n      (array_type\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nGeneric type declaration with several parameters\n================================================================================\ntype Container[T, U] = map[T]U\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (generic_parameters\n      (generic_parameter\n        (identifier))\n      (generic_parameter\n        (identifier)))\n    (plain_type\n      (map_type\n        (plain_type\n          (type_reference_expression\n            (identifier)))\n        (plain_type\n          (type_reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple sum type declaration\n================================================================================\ntype Height = string | int\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSum type declaration with several types\n================================================================================\ntype Height = string | int | float\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSum type declaration with same type\n================================================================================\ntype Height = string | int | []Height\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier))))))))\n\n================================================================================\nSum type declaration with several types on each line\n================================================================================\ntype Height = string |\n    int |\n    float\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSum type declaration with several types on each line, first line is empty\n================================================================================\ntype Height =\n    string |\n    int |\n    float\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n\n================================================================================\nSum type declaration with several types on each line and trailing pipe\n================================================================================\ntype Height =\n    string |\n    int |\n    float\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/type_initializer.txt",
    "content": "================================================================================\nSimple type initializer\n================================================================================\nFoo{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body))))\n\n================================================================================\nArray type initializer\n================================================================================\n[]int{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body))))\n\n================================================================================\nArray type initializer with field\n================================================================================\n[]int{cap: 100}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal))))))))\n\n================================================================================\nArray type initializer with fields\n================================================================================\n[]int{len: 0, cap: 100}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal))))))))\n\n================================================================================\nArray type initializer with all fields\n================================================================================\n[]int{len: 0, cap: 100, init: index * 100}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (binary_expression\n              (reference_expression\n                (identifier))\n              (literal\n                (int_literal)))))))))\n\n================================================================================\nSimple type initializer with field\n================================================================================\nFoo{\n    age: 100\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal))))))))\n\n================================================================================\nSimple type initializer with fields\n================================================================================\nFoo{\n    age: 100\n    name: \"John\"\n    weight: 100.0\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (float_literal))))))))\n\n================================================================================\nSimple type initializer with unpacking\n================================================================================\nFoo{\n    ...boo\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (spread_expression\n            (reference_expression\n              (identifier))))))))\n\n================================================================================\nSimple type initializer with unpacking and other fields\n================================================================================\nFoo{\n    ...boo\n    age: 100\n    name: \"John\"\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (spread_expression\n            (reference_expression\n              (identifier)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal))))))))\n\n================================================================================\nSimple type initializer with just value\n================================================================================\nFoo{name}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (reference_expression\n            (identifier)))))))\n\n================================================================================\nSimple type initializer with just values\n================================================================================\nFoo{name, other, 100}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (short_element_list\n          (element\n            (reference_expression\n              (identifier)))\n          (element\n            (reference_expression\n              (identifier)))\n          (element\n            (literal\n              (int_literal))))))))\n\n================================================================================\nType initializer for embedded struct\n================================================================================\nFoo{\n    Bar: Bar{\n        name: \"John\"\n        age: 100\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (type_initializer\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (type_initializer_body\n                (element_list\n                  (keyed_element\n                    (field_name\n                      (reference_expression\n                        (identifier)))\n                    (literal\n                      (interpreted_string_literal)))\n                  (keyed_element\n                    (field_name\n                      (reference_expression\n                        (identifier)))\n                    (literal\n                      (int_literal))))))))))))\n\n================================================================================\nType initializer as field for type initializer\n================================================================================\nFoo{\n    name: \"John\"\n    age: 100\n    other: Bar{\n        name: \"John\"\n        age: 100\n    }\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (type_initializer\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (type_initializer_body\n                (element_list\n                  (keyed_element\n                    (field_name\n                      (reference_expression\n                        (identifier)))\n                    (literal\n                      (interpreted_string_literal)))\n                  (keyed_element\n                    (field_name\n                      (reference_expression\n                        (identifier)))\n                    (literal\n                      (int_literal))))))))))))\n\n================================================================================\nGeneric type initializer\n================================================================================\nFoo[int, string]{\n    name: \"John\"\n    age: 100\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (generic_type\n          (type_reference_expression\n            (identifier))\n          (type_parameters\n            (plain_type\n              (type_reference_expression\n                (identifier)))\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal))))))))\n\n================================================================================\nType initializer for C structs\n================================================================================\nC.Foo{\n    name: \"John\"\n    age: 100\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (type_initializer_body\n        (element_list\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (interpreted_string_literal)))\n          (keyed_element\n            (field_name\n              (reference_expression\n                (identifier)))\n            (literal\n              (int_literal))))))))\n\n================================================================================\nType initializer for Channel type\n================================================================================\nchan f64{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (channel_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body))))\n\n================================================================================\nType initializer for Map type\n================================================================================\nmap[string]int{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (map_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (type_initializer_body))))\n\n================================================================================\nQualified type initializer\n================================================================================\npsi.StubIndexSink{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (qualified_type\n          (reference_expression\n            (identifier))\n          (type_reference_expression\n            (identifier))))\n      (type_initializer_body))))\n\n================================================================================\nQualified type initializer for pointer\n================================================================================\n&psi.StubIndexSink{}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (type_initializer\n      (plain_type\n        (pointer_type\n          (plain_type\n            (qualified_type\n              (reference_expression\n                (identifier))\n              (type_reference_expression\n                (identifier))))))\n      (type_initializer_body))))\n\n================================================================================\nDeep array initialization (TODO)\n================================================================================\n[][]u8{len: 20, cap: 20}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (index_expression\n      (array_creation)\n      (reference_expression\n        (MISSING identifier))))\n  (simple_statement\n    (reference_expression\n      (identifier)))\n  (simple_statement\n    (map_init_expression\n      (map_keyed_element\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal)))\n      (map_keyed_element\n        (reference_expression\n          (identifier))\n        (literal\n          (int_literal))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/types.txt",
    "content": "================================================================================\nSimple types\n================================================================================\nfn () int {}\nfn () string {}\nfn () f32 {}\nfn () f64 {}\nfn () Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block))))\n\n================================================================================\nBinded types\n================================================================================\nfn () C.int {}\nfn () C.Type {}\nfn () C.Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (type_reference_expression\n            (identifier))))\n      (block))))\n\n================================================================================\nQualified types\n================================================================================\nfn () mod.Foo {}\nfn () mod.string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (qualified_type\n            (reference_expression\n              (identifier))\n            (type_reference_expression\n              (identifier)))))\n      (block))))\n\n================================================================================\nPointer type\n================================================================================\nfn () &string {}\nfn () &&Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (pointer_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (pointer_type\n            (plain_type\n              (pointer_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nWrong pointer type\n================================================================================\nfn () *string {}\nfn () **Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (wrong_pointer_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (wrong_pointer_type\n            (plain_type\n              (wrong_pointer_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nArray type\n================================================================================\nfn () []string {}\nfn () [][]Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (array_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (array_type\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nFixed array type\n================================================================================\nfn () [4]string {}\nfn () [2][5]Foo {}\nfn () [const_value][5]Foo {}\nfn () [psi.const_value][5]Foo {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (fixed_array_type\n            (int_literal)\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (fixed_array_type\n            (int_literal)\n            (plain_type\n              (fixed_array_type\n                (int_literal)\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (fixed_array_type\n            (reference_expression\n              (identifier))\n            (plain_type\n              (fixed_array_type\n                (int_literal)\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (fixed_array_type\n            (selector_expression\n              (reference_expression\n                (identifier))\n              (reference_expression\n                (identifier)))\n            (plain_type\n              (fixed_array_type\n                (int_literal)\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nFunction type\n================================================================================\nfn () fn () {}\nfn () fn (string) {}\nfn () fn (int, bool) []string {}\nfn () fn (int, bool) fn (int, bool) []string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (function_type\n            (signature\n              (parameter_list)))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (function_type\n            (signature\n              (type_parameter_list\n                (type_parameter_declaration\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (function_type\n            (signature\n              (type_parameter_list\n                (type_parameter_declaration\n                  (plain_type\n                    (type_reference_expression\n                      (identifier))))\n                (type_parameter_declaration\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))\n              (plain_type\n                (array_type\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (function_type\n            (signature\n              (type_parameter_list\n                (type_parameter_declaration\n                  (plain_type\n                    (type_reference_expression\n                      (identifier))))\n                (type_parameter_declaration\n                  (plain_type\n                    (type_reference_expression\n                      (identifier)))))\n              (plain_type\n                (function_type\n                  (signature\n                    (type_parameter_list\n                      (type_parameter_declaration\n                        (plain_type\n                          (type_reference_expression\n                            (identifier))))\n                      (type_parameter_declaration\n                        (plain_type\n                          (type_reference_expression\n                            (identifier)))))\n                    (plain_type\n                      (array_type\n                        (plain_type\n                          (type_reference_expression\n                            (identifier))))))))))))\n      (block))))\n\n================================================================================\nGeneric type\n================================================================================\nfn () Foo[string] {}\nfn () mod.Bar[string, int] {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (generic_type\n            (type_reference_expression\n              (identifier))\n            (type_parameters\n              (plain_type\n                (type_reference_expression\n                  (identifier)))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (generic_type\n            (qualified_type\n              (reference_expression\n                (identifier))\n              (type_reference_expression\n                (identifier)))\n            (type_parameters\n              (plain_type\n                (type_reference_expression\n                  (identifier)))\n              (plain_type\n                (type_reference_expression\n                  (identifier)))))))\n      (block))))\n\n================================================================================\nMap type\n================================================================================\nfn () map[string]int {}\nfn () map[Foo][]int {}\nfn () map[[]Foo]map[Foo][]int {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (map_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (map_type\n            (plain_type\n              (type_reference_expression\n                (identifier)))\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (map_type\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))))\n            (plain_type\n              (map_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (array_type\n                    (plain_type\n                      (type_reference_expression\n                        (identifier))))))))))\n      (block))))\n\n================================================================================\nChannel type\n================================================================================\nfn () chan int {}\nfn () chan []string {}\nfn () chan map[Foo]string {}\nfn () chan chan string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (channel_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (channel_type\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (channel_type\n            (plain_type\n              (map_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (channel_type\n            (plain_type\n              (channel_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nShared type\n================================================================================\nfn () shared int {}\nfn () shared []string {}\nfn () shared map[Foo]string {}\nfn () shared chan string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (shared_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (shared_type\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (shared_type\n            (plain_type\n              (map_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (shared_type\n            (plain_type\n              (channel_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nThread type\n================================================================================\nfn () thread int {}\nfn () thread []string {}\nfn () thread map[Foo]string {}\nfn () thread thread string {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (thread_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (thread_type\n            (plain_type\n              (array_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (thread_type\n            (plain_type\n              (map_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (thread_type\n            (plain_type\n              (thread_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nOption type\n================================================================================\nfn (p ?int) {}\nfn () ?int {}\nfn () ?(int, string) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list\n          (parameter_declaration\n            (identifier)\n            (plain_type\n              (option_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (option_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (option_type\n            (plain_type\n              (multi_return_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nResult type\n================================================================================\nfn () !int {}\nfn () !(int, string) {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (result_type\n            (plain_type\n              (type_reference_expression\n                (identifier))))))\n      (block)))\n  (simple_statement\n    (function_literal\n      (signature\n        (parameter_list)\n        (plain_type\n          (result_type\n            (plain_type\n              (multi_return_type\n                (plain_type\n                  (type_reference_expression\n                    (identifier)))\n                (plain_type\n                  (type_reference_expression\n                    (identifier))))))))\n      (block))))\n\n================================================================================\nType union type\n================================================================================\npub type Any = Null\n\t| []Any\n\t| bool\n\t| f32\n\t| f64\n--------------------------------------------------------------------------------\n\n(source_file\n  (type_declaration\n    (visibility_modifiers)\n    (identifier)\n    (sum_type\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (array_type\n          (plain_type\n            (type_reference_expression\n              (identifier)))))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier)))\n      (plain_type\n        (type_reference_expression\n          (identifier))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/unsafe_expression.txt",
    "content": "================================================================================\nSimple unsafe expression\n================================================================================\nunsafe {}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (unsafe_expression\n      (block))))\n\n================================================================================\nSimple unsafe expression with several statements\n================================================================================\nunsafe {\n    foo()\n    bar()\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (unsafe_expression\n      (block\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))\n        (simple_statement\n          (call_expression\n            (reference_expression\n              (identifier))\n            (argument_list)))))))\n\n================================================================================\nSimple unsafe expression as an expression\n================================================================================\na := unsafe {\n    foo()\n}\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (unsafe_expression\n          (block\n            (simple_statement\n              (call_expression\n                (reference_expression\n                  (identifier))\n                (argument_list)))))))))\n"
  },
  {
    "path": "tree_sitter_v/test/corpus/var_declaration.txt",
    "content": "================================================================================\nSimple var declaration\n================================================================================\nfoo := bar\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (reference_expression\n          (identifier))))))\n\n================================================================================\nSeveral var declarations\n================================================================================\nfoo, goo, poo := bar, far, tar\n--------------------------------------------------------------------------------\n\n(source_file\n  (simple_statement\n    (var_declaration\n      (expression_list\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier)))\n      (expression_list\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier))\n        (reference_expression\n          (identifier))))))\n"
  },
  {
    "path": "tree_sitter_v/tree-sitter.json",
    "content": "{\n  \"grammars\": [\n    {\n      \"name\": \"v\",\n      \"camelcase\": \"V\",\n      \"scope\": \"source.v\",\n      \"path\": \".\",\n      \"file-types\": [\n        \"v\",\n        \"vsh\",\n        \"v.mod\"\n      ]\n    }\n  ],\n  \"metadata\": {\n    \"version\": \"0.0.6\",\n    \"license\": \"MIT\",\n    \"description\": \"V grammar for tree-sitter\",\n    \"links\": {\n      \"repository\": \"https://github.com/vlang/v-analyzer.git\"\n    }\n  }\n}\n"
  },
  {
    "path": "v.mod",
    "content": "Module {\n\tname: 'v-analyzer'\n\tdescription: 'Language server implementation for the V (vlang) programming language'\n\tversion: '0.0.6'\n\tlicense: 'MIT'\n\tdependencies: []\n}\n"
  }
]